aboutsummaryrefslogtreecommitdiffstats
path: root/champ-lib/champ-core
diff options
context:
space:
mode:
Diffstat (limited to 'champ-lib/champ-core')
-rw-r--r--champ-lib/champ-core/License.txt21
-rw-r--r--champ-lib/champ-core/pom.xml119
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampAPI.java51
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampCapabilities.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampGraph.java627
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampTransaction.java73
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/FormatMapper.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/Formatter.java77
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/NoOpTinkerPopTransaction.java57
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/AbstractLoggingChampGraph.java792
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/ChampEvent.java213
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampIndexNotExistsException.java41
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampMarshallingException.java41
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampObjectNotExistsException.java41
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampRelationshipNotExistsException.java41
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampSchemaViolationException.java41
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampTransactionException.java41
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampUnmarshallingException.java41
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractTinkerpopChampGraph.java1068
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractValidatingChampGraph.java293
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/ChampAPIImpl.java88
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/InMemoryChampGraphImpl.java209
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/TinkerpopTransaction.java164
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Exporter.java31
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/GraphMLImporterExporter.java471
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Importer.java31
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampCardinality.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionConstraint.java96
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionMultiplicity.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampElement.java35
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampField.java129
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObject.java280
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectConstraint.java107
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectIndex.java87
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPartition.java148
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPropertyConstraint.java110
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationship.java220
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipConstraint.java139
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipIndex.java87
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampSchema.java148
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/BuildStep.java26
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/KeyStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/PropertiesStep.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateObjectIndexable.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateRelationshipIndexable.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexFieldStep.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexTypeStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexFieldStep.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexTypeStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateObjectIndexableImpl.java77
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateRelationshipIndexableImpl.java58
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/CreateChampObjectable.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStep.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java53
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectKeyStepImpl.java47
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/impl/CreateChampObjectableImpl.java42
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/CreateChampPartitionable.java34
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/impl/CreateChampPartionableImpl.java53
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/CreateChampRelationshipable.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java29
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceBuildOrPropertiesStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceFromStep.java29
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceKeyStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceStep.java26
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeOrFromStep.java26
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetBuildOrPropertiesStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetFromStep.java29
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetKeyStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetStep.java26
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeOrFromStep.java26
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java53
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java53
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java54
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java55
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceKeyStepImpl.java56
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceStepImpl.java45
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java53
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java65
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetKeyStepImpl.java56
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetStepImpl.java49
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java55
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/CreateChampSchemable.java31
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintBuildStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldTypeStep.java29
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintPropertyStep.java29
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java31
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintSubStep.java26
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintTypeStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintBuildStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldTypeStep.java29
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintMultiplicityStep.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java25
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSourceStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSubStep.java30
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTargetStep.java28
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTypeStep.java27
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/CreateChampSchemableImpl.java74
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java43
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java45
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java50
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java111
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java45
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java68
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java64
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java205
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/AlwaysValidChampSchemaEnforcer.java45
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/ChampSchemaEnforcer.java37
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/DefaultChampSchemaEnforcer.java144
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/Champformer.java34
-rw-r--r--champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/TinkerpopChampformer.java94
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/concurrency/ConcurrencyTest.java74
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/BaseChampAPITest.java34
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampAPITest.java242
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampElementTest.java62
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampFieldTest.java53
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectIndexTest.java134
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectTest.java359
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPartitionTest.java226
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPropertyConstraintTest.java57
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipIndexTest.java179
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipTest.java310
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampSchemaTest.java759
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampTransactionTest.java502
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/event/AbstractLoggingChampGraphTest.java1181
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/exceptions/ChampExceptionTest.java150
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ExportTest.java41
-rw-r--r--champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ImportTest.java94
-rw-r--r--champ-lib/champ-core/src/test/resources/import-test.graphml49
-rw-r--r--champ-lib/champ-core/src/test/resources/logback.xml43
134 files changed, 14144 insertions, 0 deletions
diff --git a/champ-lib/champ-core/License.txt b/champ-lib/champ-core/License.txt
new file mode 100644
index 0000000..469f362
--- /dev/null
+++ b/champ-lib/champ-core/License.txt
@@ -0,0 +1,21 @@
+============LICENSE_START==========================================
+org.onap.aai
+===================================================================
+Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+Copyright © 2017 Amdocs
+===================================================================
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+============LICENSE_END============================================
+ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+
diff --git a/champ-lib/champ-core/pom.xml b/champ-lib/champ-core/pom.xml
new file mode 100644
index 0000000..b52f408
--- /dev/null
+++ b/champ-lib/champ-core/pom.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>
+ <artifactId>champ-lib</artifactId>
+ <groupId>org.onap.aai</groupId>
+ <version>1.2.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>champ-core</artifactId>
+
+ <dependencies>
+ <!-- Event Bus Library. -->
+ <dependency>
+ <groupId>org.onap.aai.event-client</groupId>
+ <artifactId>event-client-api</artifactId>
+ <version>${event.client.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.aai.event-client</groupId>
+ <artifactId>event-client-dmaap</artifactId>
+ <version>${event.client.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.aai.event-client</groupId>
+ <artifactId>event-client-kafka</artifactId>
+ <version>${event.client.version}</version>
+ </dependency>
+ <!-- Event Bus Library - END -->
+
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy</artifactId>
+ <version>2.4.12</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>2.5.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tinkerpop</groupId>
+ <artifactId>gremlin-core</artifactId>
+ <version>3.2.3</version>
+ <optional>true</optional>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tinkerpop</groupId>
+ <artifactId>tinkergraph-gremlin</artifactId>
+ <version>3.2.3</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.8.2</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.0.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.mycila</groupId>
+ <artifactId>license-maven-plugin</artifactId>
+ <version>3.0</version>
+ <configuration>
+ <header>License.txt</header>
+ <includes>
+ <include>**/*.java</include>
+ <include>**/*.ksh</include>
+ <include>**/*.sh</include>
+ <include>**/*.ftl</include>
+ <include>**/*.xsd</include>
+ <include>**/*.xjb</include>
+ <include>**/*.yml</include>
+ <include>**/*.yaml</include>
+ <include>**/aai*.xml</include>
+ <include>**/*logback*.xml</include>
+ <include>**/*aaiconfig*.properties</include>
+ <include>**/*titan*.properties</include>
+ </includes>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>format</goal>
+ </goals>
+ <phase>process-sources</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampAPI.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampAPI.java
new file mode 100644
index 0000000..719306f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampAPI.java
@@ -0,0 +1,51 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore;
+
+import org.onap.aai.champcore.graph.impl.ChampAPIImpl;
+
+public interface ChampAPI {
+
+ /**
+ * A factory for constructing basic ChampAPI implementations (minimal).
+ * If finer control is needed, you should consider accessing an implementation's
+ * constructors/builders.
+ */
+ public static final class Factory {
+ private Factory() { throw new RuntimeException("Cannot instantiate ChampAPI.Factory"); }
+
+ public static ChampAPI newInstance(String type) {
+ return new ChampAPIImpl(type);
+ }
+ }
+
+ public ChampGraph getGraph(String graphName);
+
+ public String getType();
+
+ /**
+ * Shutdown the ChampAPI. It is up to the caller to synchronize access to the ChampAPI
+ * so that shutting it down does not interfere with concurrent operations.
+ */
+ public void shutdown();
+}
+
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampCapabilities.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampCapabilities.java
new file mode 100644
index 0000000..b0c62cb
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampCapabilities.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore;
+
+public interface ChampCapabilities {
+
+ public boolean canDeleteObjectIndices();
+ public boolean canDeleteRelationshipIndices();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampGraph.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampGraph.java
new file mode 100644
index 0000000..74c1cf8
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampGraph.java
@@ -0,0 +1,627 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+import org.onap.aai.champcore.model.ChampSchema;
+
+public interface ChampGraph {
+
+ /**
+ * Opens a transaction within the graph data store.
+ *
+ * @return - A transaction object.
+ */
+ public ChampTransaction openTransaction();
+
+ /**
+ * Attempts to commit the supplied open transaction.
+ *
+ * @param transaction - The transaction to be committed.
+ *
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public void commitTransaction(ChampTransaction transaction) throws ChampTransactionException;
+
+ /**
+ * Attempts to roll back the supplied open transaction.
+ *
+ * @param transaction - The transaction to be committed.
+ *
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public void rollbackTransaction(ChampTransaction transaction) throws ChampTransactionException;
+
+ /**
+ * Create/Update an object.
+ * <p>
+ * If the ChampObject key is present, an update will be attempted,
+ * otherwise a create will be attempted. Each implementation has different guarantees on
+ * validation - see the specific implementation for more details on this.
+ *
+ * @param object - The ChampObject that you wish to store in the graph
+ *
+ * @return The ChampObject as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code object} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code object} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException If {@link org.onap.aai.champcore.model.ChampObject#getKey}.isPresent() but the object cannot be found in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampObject storeObject(ChampObject object) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Create/Update an object.
+ * <p>
+ * If the ChampObject key is present, an update will be attempted,
+ * otherwise a create will be attempted. Each implementation has different guarantees on
+ * validation - see the specific implementation for more details on this.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param object - The ChampObject that you wish to store in the graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return The ChampObject as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code object} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code object} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException If {@link org.onap.aai.champcore.model.ChampObject#getKey}.isPresent() but the object cannot be found in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampObject storeObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Replace an object. ChampObject key is mandatory
+ * <p>
+ * Each implementation has different guarantees on validation - see the specific implementation
+ * for more details on this.
+ *
+ * @param object - The ChampObject that you wish to replace in the graph
+ *
+ * @return The ChampObject as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code object} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code object} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException If {@link org.onap.aai.champcore.model.ChampObject#getKey} is not present or object not found in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampObject replaceObject(ChampObject object) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Replace an object. ChampObject key is mandatory
+ * <p>
+ * Each implementation has different guarantees on validation - see the specific implementation
+ * for more details on this.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param object - The ChampObject that you wish to replace in the graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return The ChampObject as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code object} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code object} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException If {@link org.onap.aai.champcore.model.ChampObject#getKey} is not present or object not found in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampObject replaceObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Retrieve an object by its key.
+ *
+ * @param key - The key of the ChampObject in the graph {@link org.onap.aai.champcore.model.ChampObject#getKey()}
+ *
+ * @return The {@link org.onap.aai.champcore.model.ChampObject} if it was present, otherwise {@link Optional#empty()}
+ *
+ * @throws ChampUnmarshallingException If the object was found, but could not be unmarshalled
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException, ChampTransactionException;
+
+
+ /**
+ * Retrieve an object by its key.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param key - The key of the ChampObject in the graph {@link org.onap.aai.champcore.model.ChampObject#getKey()}
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return The {@link org.onap.aai.champcore.model.ChampObject} if it was present, otherwise {@link Optional#empty()}
+ *
+ * @throws ChampUnmarshallingException If the object was found, but could not be unmarshalled
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Optional<ChampObject> retrieveObject(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException;
+
+ /**
+ * Delete an object by its key.
+ *
+ * @param key - The key of the ChampObject in the graph {@link ChampObject#getKey}
+ *
+ * @throws ChampObjectNotExistsException If the object did not exist in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public void deleteObject(Object key) throws ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Delete an object by its key.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param key - The key of the ChampObject in the graph {@link ChampObject#getKey}
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @throws ChampObjectNotExistsException If the object did not exist in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public void deleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Retrieve all the objects whose properties match the given {@code queryParams}
+ *
+ * @param queryParams - The key/value pairs which are found in {@link ChampObject#getProperties}
+ *
+ * @return - A {@link Stream} where each {@link ChampObject#getProperties} contains the {@code queryParams}
+ *
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) throws ChampTransactionException;
+
+
+ /**
+ * Retrieve all the objects whose properties match the given {@code queryParams}
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param queryParams - The key/value pairs which are found in {@link ChampObject#getProperties}
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - A {@link Stream} where each {@link ChampObject#getProperties} contains the {@code queryParams}
+ *
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Stream<ChampObject> queryObjects(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException;
+
+ /**
+ * Create/Update a relationship.
+ * <p>
+ * If the ChampRelationship key is present, an update will be attempted,
+ * otherwise a create will be attempted. Each implementation has different guarantees on
+ * validation - see the specific implementation for more details on this.
+ *
+ * @param relationship - The ChampRelationship that you wish to store in the graph
+ *
+ * @return The ChampRelationship as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code relationship} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code relationship} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException If either the source or target object referenced by this relationship does not exist in the graph
+ * @throws ChampRelationshipNotExistsException If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent() but the object cannot be found in the graph
+ * @throws ChampUnmarshallingException If the edge which was created could not be unmarshalled into a ChampRelationship
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampRelationship storeRelationship(ChampRelationship relationship) throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException;
+
+
+ /**
+ * Create/Update a relationship.
+ * <p>
+ * If the ChampRelationship key is present, an update will be attempted,
+ * otherwise a create will be attempted. Each implementation has different guarantees on
+ * validation - see the specific implementation for more details on this.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The ChampRelationship that you wish to store in the graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return The ChampRelationship as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code relationship} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code relationship} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException If either the source or target object referenced by this relationship does not exist in the graph
+ * @throws ChampRelationshipNotExistsException If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent() but the object cannot be found in the graph
+ * @throws ChampUnmarshallingException If the edge which was created could not be unmarshalled into a ChampRelationship
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampRelationship storeRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException;
+
+ /**
+ * Replace a relationship.
+ * <p>
+ * ChampRelationship key is mandatory. The main purpose of this method is to replace the
+ * entire properties of an existing relationship. Source/Target can't be updated with this method.
+ * <p>
+ * Each implementation has different guarantees on validation - see the specific implementation
+ * for more details on this.
+ *
+ * @param relationship - The ChampRelationship that you wish to replace in the graph
+ *
+ * @return The ChampRelationship as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code relationship} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code relationship} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampRelationshipNotExistsException If {@link org.onap.aai.champcore.model.ChampRelationship#getKey} is not present or object not found in the graph
+ * @throws ChampUnmarshallingException If the edge which was created could not be unmarshalled into a ChampRelationship
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampRelationship replaceRelationship(ChampRelationship relationship) throws ChampMarshallingException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException;
+
+ /**
+ * Replace a relationship.
+ * <p>
+ * ChampRelationship key is mandatory. The main purpose of this method is to replace the
+ * entire properties of an existing relationship. Source/Target can't be updated with this method.
+ * <p>
+ * Each implementation has different guarantees on validation - see the specific implementation
+ * for more details on this.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The ChampRelationship that you wish to replace in the graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return The ChampRelationship as it was stored
+ *
+ * @throws ChampMarshallingException If the {@code relationship} is not able to be marshalled into the backend representation
+ * @throws ChampSchemaViolationException If the {@code relationship} violates the constraints specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampRelationshipNotExistsException If {@link org.onap.aai.champcore.model.ChampRelationship#getKey} is not present or object not found in the graph
+ * @throws ChampUnmarshallingException If the edge which was created could not be unmarshalled into a ChampRelationship
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public ChampRelationship replaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException;
+
+ /**
+ * Retrieve a relationship by its key.
+ *
+ * @param key - The key of the ChampRelationship in the graph
+ * {@link org.onap.aai.champcore.model.ChampRelationship#getKey()}
+ *
+ * @return The {@link org.onap.aai.champcore.model.ChampRelationship} if it was present, otherwise {@link Optional#empty()}
+ *
+ * @throws ChampUnmarshallingException If the relationship was found, but could not be unmarshalled
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Optional<ChampRelationship> retrieveRelationship(Object key) throws ChampUnmarshallingException, ChampTransactionException;
+
+
+ /**
+ * Retrieve a relationship by its key.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param key - The key of the ChampRelationship in the graph
+ * {@link org.onap.aai.champcore.model.ChampRelationship#getKey()}
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return The {@link org.onap.aai.champcore.model.ChampRelationship} if it was present, otherwise {@link Optional#empty()}
+ *
+ * @throws ChampUnmarshallingException If the relationship was found, but could not be unmarshalled
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Optional<ChampRelationship> retrieveRelationship(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException;
+
+ /**
+ * Delete a relationship by its key.
+ *
+ * @param relationship - The ChampRelationship in the graph ({@link ChampRelationship#getKey must be present})
+ *
+ * @throws ChampRelationshipNotExistsException If the object did not exist in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public void deleteRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException, ChampTransactionException;
+
+ /**
+ * Delete a relationship by its key.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The ChampRelationship in the graph ({@link ChampRelationship#getKey must be present})
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @throws ChampRelationshipNotExistsException If the object did not exist in the graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public void deleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampTransactionException;
+
+ /**
+ * Retrieve the relationships which are incident to the {@code object}
+ *
+ * @param object - The object you wish to find incident relationships for
+ *
+ * @return A {@link Stream} where each {@link ChampRelationship} has this {@code object} as either a source or target object
+ *
+ * @throws ChampUnmarshallingException If any of the ChampRelationship objects could not be unmarshalled
+ * @throws ChampObjectNotExistsException If the {@code object} does not exist in this graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Stream<ChampRelationship> retrieveRelationships(ChampObject object) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException;
+
+
+ /**
+ * Retrieve the relationships which are incident to the {@code object}
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param object - The object you wish to find incident relationships for
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return A {@link Stream} where each {@link ChampRelationship} has this {@code object} as either a source or target object
+ *
+ * @throws ChampUnmarshallingException If any of the ChampRelationship objects could not be unmarshalled
+ * @throws ChampObjectNotExistsException If the {@code object} does not exist in this graph
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Stream<ChampRelationship> retrieveRelationships(ChampObject object, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Retrieve the relationships whose properties match the given {@code queryParams}
+ *
+ * @param queryParams - The key/value pairs to search for in the {@link ChampRelationship#getProperties}
+ *
+ * @return A {@link Stream} where each {@link ChampRelationship#getProperties} contains the {@code queryParams}
+ *
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) throws ChampTransactionException;
+
+ /**
+ * Retrieve the relationships whose properties match the given {@code queryParams}
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param queryParams - The key/value pairs to search for in the {@link ChampRelationship#getProperties}
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return A {@link Stream} where each {@link ChampRelationship#getProperties} contains the {@code queryParams}
+ *
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException;
+
+ /**
+ * Create/Update a {@link ChampPartition}. If any of the ChampObjects or ChampRelationships
+ * present in this ChampPartition already exist, an update will be attempted, otherwise a create
+ * will be attempted.
+ * <p>
+ * Each implementation has different guarantees on validation -
+ * see the specific implementation details for more information on this.
+ *
+ * @param partition - The ChampPartition you wish to store in this graph
+ *
+ * @throws ChampMarshallingException If any of the objects or relationships contained in this
+ * partition could not be marshalled into its backed representation
+ * @throws ChampObjectNotExistsException If any of the objects being updated do not exist, or if a relationship
+ * contain objects which do not exist in the graph.
+ * @throws ChampSchemaViolationException If any of the objects or relationships violate the schema provided by {@link retrieveSchema}
+ * @throws ChampRelationshipNotExistsException If any of the relationships which are being updated do not exist
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ *
+ * @return The ChampPartition as is was stored in the graph (contains keys for each newly created object)
+ */
+ public ChampPartition storePartition(ChampPartition partition) throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampTransactionException;
+
+ /**
+ * Create/Update a {@link ChampPartition}. If any of the ChampObjects or ChampRelationships
+ * present in this ChampPartition already exist, an update will be attempted, otherwise a create
+ * will be attempted.
+ * <p>
+ * Each implementation has different guarantees on validation -
+ * see the specific implementation details for more information on this.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param partition - The ChampPartition you wish to store in this graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @throws ChampMarshallingException If any of the objects or relationships contained in this
+ * partition could not be marshalled into its backed representation
+ * @throws ChampObjectNotExistsException If any of the objects being updated do not exist, or if a relationship
+ * contain objects which do not exist in the graph.
+ * @throws ChampSchemaViolationException If any of the objects or relationships violate the schema provided by {@link retrieveSchema}
+ * @throws ChampRelationshipNotExistsException If any of the relationships which are being updated do not exist
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ *
+ * @return The ChampPartition as is was stored in the graph (contains keys for each newly created object)
+ */
+ public ChampPartition storePartition(ChampPartition partition, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampTransactionException;
+
+ /**
+ * Delete the {@code partition} from the graph.
+ *
+ * @param partition - The partition to delete from the graph
+ *
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public void deletePartition(ChampPartition partition) throws ChampTransactionException;
+
+ /**
+ * Delete the {@code partition} from the graph.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param partition - The partition to delete from the graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @throws ChampTransactionException If an attempt to commit or rollback the transaction failed.
+ */
+ public void deletePartition(ChampPartition partition, Optional<ChampTransaction> transaction) throws ChampTransactionException;
+
+ /**
+ * Create/Update an object index on the graph
+ * @param index - The index to create on this {@code graph}
+ */
+ public void storeObjectIndex(ChampObjectIndex index);
+
+ /**
+ * Retrieve an object index on the graph by its {@code indexName}
+ * @param indexName The name of the index to retrieve from the graph
+ * @return The {@link ChampObjectIndex} which matches the given @{code indexName} in the graph
+ */
+ public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName);
+
+ /**
+ * Retrieve the object indices on the graph
+ * @return A {@link Stream} where each {@link ChampObjectIndex} exists in the graph
+ */
+ public Stream<ChampObjectIndex> retrieveObjectIndices();
+
+ /**
+ * Delete the object index on the graph by its {@code indexName}
+ * @param indexName The name of the index to delete from the graph
+ * @throws ChampIndexNotExistsException If an index does not exist with the given {@code indexName} in the graph
+ */
+ public void deleteObjectIndex(String indexName) throws ChampIndexNotExistsException;
+
+ /**
+ * Create/Update a relationship index on the graph
+ * @param index The relationship index to create on the graph
+ */
+ public void storeRelationshipIndex(ChampRelationshipIndex index);
+
+ /**
+ * Retrieve a relationship index from the graph
+ * @param indexName The name of the relationship index to retrieve from the graph
+ * @return The {@link ChampRelationshipIndex} which matches the given {@code indexName} in the graph
+ * or {@link Optional#empty} if no such relationship index exists
+ */
+ public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName);
+
+ /**
+ * Retrieve the relationship indices from the graph
+ * @return A {@link Stream} where each {@link ChampRelationshipIndex} exists in the graph
+ */
+ public Stream<ChampRelationshipIndex> retrieveRelationshipIndices();
+
+ /**
+ * Delete a relationship index from the graph
+ * @param indexName THe name of the index to delete from the graph
+ * @throws ChampIndexNotExistsException If an index does not exist with the give {@code indexName} in the graph
+ */
+ public void deleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException;
+
+ /**
+ * Create/Update the schema for a graph
+ * @param schema The {@link ChampSchema} to create or update on the graph
+ * @throws ChampSchemaViolationException If this schema update would violate the current schema
+ */
+ public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException;
+
+ /**
+ * Retrieve the schema for a graph
+ * @return The {@link ChampSchema} for the graph
+ */
+ public ChampSchema retrieveSchema();
+
+ /**
+ * Create/Update an object constraint on a schema
+ * @param objectConstraint The object constraint you wish to create/update for the graph
+ * @throws ChampSchemaViolationException If this schema update would violate the current schema
+ */
+ public void updateSchema(ChampObjectConstraint objectConstraint) throws ChampSchemaViolationException;
+
+ /**
+ * Create/Update a relationship constraint on a schema
+ * @param schema The relationship constraint you wish to create/update for the graph
+ * @throws ChampSchemaViolationException If this schema update would violate the current schema
+ */
+ public void updateSchema(ChampRelationshipConstraint schema) throws ChampSchemaViolationException;
+
+ /**
+ * Delete the schema for a graph
+ */
+ public void deleteSchema();
+
+ /**
+ * Shutdown the ChampAPI. It is up to the caller to synchronize access to the ChampAPI
+ * so that shutting it down does not interfere with concurrent operations.
+ */
+ public void shutdown();
+
+ /**
+ * Used to determine what the outcome of certain ChampGraph operations will be. For example,
+ * if this graph is not capable of deleting object indices, you can expect those calls to fail.
+ * @see ChampCapabilities
+ * @return What this graph is capable of performing
+ */
+ public ChampCapabilities capabilities();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampTransaction.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampTransaction.java
new file mode 100644
index 0000000..5dab092
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampTransaction.java
@@ -0,0 +1,73 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import org.onap.aai.champcore.event.ChampEvent;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+
+/**
+ * This class defines the interface for a graph transaction object.
+ */
+public abstract class ChampTransaction {
+
+ /** Unique identifier for this transaction (largely for logging purposes). */
+ protected UUID id;
+
+ protected List<ChampEvent> eventList = Collections.synchronizedList(new ArrayList<ChampEvent>());
+
+ public ChampTransaction() {
+
+ // Create a unique identifier for this transaction.
+ id = UUID.randomUUID();
+ }
+
+ public String id() {
+ return id.toString();
+ }
+
+ public void logEvent(ChampEvent event) {
+ eventList.add(event);
+ }
+
+ public List<ChampEvent> getEnqueuedEvents() {
+ return eventList;
+ }
+
+ /**
+ * Finalize all updates to the graph which have been made within the context
+ * of this transaction.
+ */
+ public abstract void commit() throws ChampTransactionException ;
+
+
+ /**
+ * Aborts all graph changes made within the context of this transaction, backing
+ * out all changes as if they had never happened.
+ */
+ public abstract void rollback() throws ChampTransactionException ;
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/FormatMapper.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/FormatMapper.java
new file mode 100644
index 0000000..6d4db09
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/FormatMapper.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore;
+
+import com.google.gson.JsonObject;
+
+public interface FormatMapper {
+ JsonObject formatObject( Object var1) throws Exception;
+
+ int parallelThreshold();
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/Formatter.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/Formatter.java
new file mode 100644
index 0000000..a6292f3
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/Formatter.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class Formatter {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Formatter.class);
+ protected JsonParser parser = new JsonParser();
+ protected final FormatMapper format;
+
+ public Formatter(FormatMapper format) {
+ this.format = format;
+ }
+
+ public JsonObject output(List<Object> vertices) {
+ Stream<Object> stream = null;
+ JsonObject result = new JsonObject();
+ JsonArray body = new JsonArray();
+ if (vertices.size() >= this.format.parallelThreshold()) {
+ stream = vertices.parallelStream();
+ } else {
+ stream = vertices.stream();
+ }
+
+ boolean isParallel = stream.isParallel();
+ stream.map((v) -> {
+ try {
+ return Optional.of(this.format.formatObject(v));
+ } catch (Exception var3) {
+ LOGGER.warn("Failed to format vertex, returning a partial list", var3);
+ return Optional.empty();
+ }
+ }).forEach((obj) -> {
+ if (obj.isPresent()) {
+ if (isParallel) {
+ synchronized(body) {
+ body.add((JsonElement)obj.get());
+ }
+ } else {
+ body.add((JsonElement)obj.get());
+ }
+ }
+
+ });
+ result.add("results", body);
+ return result.getAsJsonObject();
+ }
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/NoOpTinkerPopTransaction.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/NoOpTinkerPopTransaction.java
new file mode 100644
index 0000000..208b2d1
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/NoOpTinkerPopTransaction.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore;
+
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.onap.aai.champcore.graph.impl.TinkerpopTransaction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NoOpTinkerPopTransaction extends TinkerpopTransaction {
+
+ protected Graph graph;
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NoOpTinkerPopTransaction.class);
+
+
+ public NoOpTinkerPopTransaction(Graph aGraphInstance) {
+
+ this.graph = aGraphInstance;
+ }
+
+ public Graph getGraphInstance() {
+ return graph;
+ }
+
+ @Override
+ public void commit() {
+ // Do nothing.
+ }
+
+ @Override
+ public void rollback() {
+
+
+ // Do nothing.
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/AbstractLoggingChampGraph.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/AbstractLoggingChampGraph.java
new file mode 100644
index 0000000..79a7f3c
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/AbstractLoggingChampGraph.java
@@ -0,0 +1,792 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.event;
+
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+
+import org.onap.aai.champcore.ChampCapabilities;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.event.ChampEvent.ChampOperation;
+import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.onap.aai.event.api.EventPublisher;
+
+
+
+/**
+ * This class provides the hooks to allow Champ operations to be logged to an event
+ * stream.
+ */
+public abstract class AbstractLoggingChampGraph implements ChampGraph {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractLoggingChampGraph.class);
+
+ public abstract Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException, ChampTransactionException;
+ public abstract Optional<ChampObject> retrieveObject(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException;
+ public abstract Stream<ChampObject> queryObjects(Map<String, Object> queryParams) throws ChampTransactionException;
+ public abstract Stream<ChampObject> queryObjects(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException;
+ @Override
+ public abstract Optional<ChampRelationship> retrieveRelationship(Object key) throws ChampUnmarshallingException, ChampTransactionException;
+ @Override
+ public abstract Optional<ChampRelationship> retrieveRelationship(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException;
+ public abstract Stream<ChampRelationship> retrieveRelationships(ChampObject object) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException;
+ public abstract Stream<ChampRelationship> retrieveRelationships(ChampObject object, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException;
+ public abstract Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) throws ChampTransactionException;
+ public abstract Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException;
+
+
+ /**
+ * Creates or updates a vertex in the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param object - The vertex to be created or updated.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The vertex, as created, marshaled as a {@link ChampObject}
+ *
+ * @throws ChampMarshallingException - If the {@code object} is not able to be marshalled
+ * into the backend representation
+ * @throws ChampSchemaViolationException - If the {@code object} violates the constraints specifed
+ * by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException - If {@link org.onap.aai.champcore.model.ChampObject#getKey}
+ * is not present or object not found in the graph
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract ChampObject executeStoreObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Updates an existing vertex in the graph store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param object - The vertex to be created or updated.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The updated vertex, marshaled as a {@link ChampObject}
+ *
+ * @throws ChampMarshallingException - If the {@code object} is not able to be marshalled into
+ * the backend representation
+ * @throws ChampSchemaViolationException - If the {@code object} violates the constraints specifed
+ * by {@link ChampGraph#retrieveSchema}
+ * @throws ChampObjectNotExistsException - If {@link org.onap.aai.champcore.model.ChampObject#getKey}
+ * is not present or object not found in the graph
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract ChampObject executeReplaceObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Deletes an existing vertex from the graph store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param key - The key of the ChampObject in the graph {@link ChampObject#getKey}
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @throws ChampObjectNotExistsException - If {@link org.onap.aai.champcore.model.ChampObject#getKey}
+ * is not present or object not found in the graph
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract void executeDeleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Creates or updates an edge in the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The ChampRelationship that you wish to store in the graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The {@link ChampRelationship} as it was stored.
+ *
+ * @throws ChampUnmarshallingException - If the edge which was created could not be
+ * unmarshalled into a ChampRelationship
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshalled into the backend representation
+ * @throws ChampObjectNotExistsException - If either the source or target object referenced
+ * by this relationship does not exist in the graph
+ * @throws ChampSchemaViolationException - If the {@code relationship} violates the constraints
+ * specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampRelationshipNotExistsException - If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent()
+ * but the object cannot be found in the graph
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract ChampRelationship executeStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampTransactionException;
+
+ /**
+ * Replaces an existing edge in the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The ChampRelationship that you wish to replace in the graph
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The {@link ChampRelationship} as it was stored.
+ *
+ * @throws ChampUnmarshallingException - If the edge which was created could not be
+ * unmarshalled into a ChampRelationship
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshalled into the backend representation
+ * @throws ChampSchemaViolationException - If the {@code relationship} violates the constraints
+ * specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampRelationshipNotExistsException - If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent()
+ * but the object cannot be found in the graph
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract ChampRelationship executeReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampMarshallingException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampTransactionException;
+
+ /**
+ * Removes an edge from the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The ChampRelationship that you wish to remove from the graph.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @throws ChampRelationshipNotExistsException - If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent()
+ * but the object cannot be found in the graph
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract void executeDeleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampTransactionException;
+
+ /**
+ * Create or update a {@link ChampPartition}.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param partition - The ChampPartition that you wish to create or update in the graph.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The {@link ChampPartition} as it was stored.
+ *
+ * @throws ChampSchemaViolationException - If the {@code relationship} violates the constraints
+ * specifed by {@link ChampGraph#retrieveSchema}
+ * @throws ChampRelationshipNotExistsException - If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent()
+ * but the object cannot be found in the graph
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshalled into the backend representation
+ * @throws ChampObjectNotExistsException - If either the source or target object referenced
+ * by this relationship does not exist in the graph
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract ChampPartition executeStorePartition(ChampPartition partition, Optional<ChampTransaction> transaction) throws ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Removes a partition from the graph.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param graph - The partition to be removed.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @throws ChampTransactionException - If an attempt to commit or rollback the transaction failed.
+ */
+ public abstract void executeDeletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) throws ChampTransactionException;
+
+ /**
+ * Create or update an object index in the graph.
+ *
+ * @param index - The object index to be created/updated.
+ */
+ public abstract void executeStoreObjectIndex(ChampObjectIndex index);
+
+ public abstract Optional<ChampObjectIndex> retrieveObjectIndex(String indexName);
+ public abstract Stream<ChampObjectIndex> retrieveObjectIndices();
+ public abstract void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException;
+ public abstract void executeStoreRelationshipIndex(ChampRelationshipIndex index);
+ public abstract Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName);
+ public abstract Stream<ChampRelationshipIndex> retrieveRelationshipIndices();
+ public abstract void executeDeleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException;
+ public abstract void storeSchema(ChampSchema schema) throws ChampSchemaViolationException;
+ public abstract ChampSchema retrieveSchema();
+ public abstract void updateSchema(ChampObjectConstraint objectConstraint) throws ChampSchemaViolationException;
+ public abstract void updateSchema(ChampRelationshipConstraint schema) throws ChampSchemaViolationException;
+ public abstract void deleteSchema();
+ public abstract ChampCapabilities capabilities();
+
+
+
+ public final static String PARAM_EVENT_QUEUE_CAPACITY = "champcore.event.stream.buffer.capacity";
+ public final static Integer DEFAULT_EVENT_QUEUE_CAPACITY = 10000;
+
+ public final static String PARAM_EVENT_STREAM_PUBLISHER_POOL_SIZE = "champcore.event.stream.publisher-pool-size";
+ public final static Integer DEFAULT_EVENT_STREAM_PUBLISHER_POOL_SIZE = 5;
+
+ public final static String PARAM_EVENT_STREAM_PRODUCER = "champcore.event.stream.publisher";
+
+
+
+ /** Number of events that can be queued up for publication before we begin dropping
+ * events. */
+ private Integer eventQueueCapacity;
+
+ /** Number of event publisher worker threads. */
+ private Integer eventStreamPublisherPoolSize;
+
+ /** Pool of worker threads that do the work of publishing the events to the event bus. */
+ protected ThreadPoolExecutor publisherPool;
+
+ /** Client used for publishing events to the event bus. */
+ protected EventPublisher producer;
+
+ /** Internal queue where outgoing events will be buffered until they can be serviced by
+ * the event publisher worker threads. */
+ protected BlockingQueue<ChampEvent> eventQueue;
+
+
+ /**
+ * Thread factory for the event producer workers.
+ */
+ private class ProducerWorkerThreadFactory implements ThreadFactory {
+
+ private AtomicInteger threadNumber = new AtomicInteger(1);
+
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "champEventStreamPublisher-" + threadNumber.getAndIncrement());
+ }
+ }
+
+
+ /**
+ * Create a new instance of the AbstractLoggingChampGraph.
+ *
+ * @param properties - Set of configuration properties for this graph instance.
+ */
+ protected AbstractLoggingChampGraph(Map<String, Object> properties) {
+
+ // Extract the necessary parameters from the configuration properties.
+ configure(properties);
+
+ // Make sure we were passed an event producer as one of our properties, otherwise
+ // there is really nothing more we can do...
+ if(producer == null) {
+ logger.error("No event stream producer was supplied.");
+ logger.error("NOTE!! Champ events will NOT be published to the event stream!");
+ return;
+ }
+
+ // Create the blocking queue that we will use to buffer events that we want
+ // published to the event bus.
+ eventQueue = new ArrayBlockingQueue<ChampEvent>(eventQueueCapacity);
+
+ // Create the executor pool that will do the work of publishing events to the event bus.
+ publisherPool =
+ (ThreadPoolExecutor) Executors.newFixedThreadPool(eventStreamPublisherPoolSize,
+ new ProducerWorkerThreadFactory());
+
+ try {
+
+ // Start up the producer worker threads.
+ for(int i=0; i<eventStreamPublisherPoolSize; i++) {
+ publisherPool.submit(new EventPublisherWorker());
+ }
+
+ } catch (Exception e) {
+
+ logger.error("Failed to instantiate event stream producer thread due to: '" + e.getMessage() + "'");
+ logger.error("NOTE!! Champ events may NOT be published to the event stream!");
+ return;
+ }
+ }
+
+
+ /**
+ * Process the configuration properties supplied for this graph instance.
+ *
+ * @param properties - Configuration parameters.
+ */
+ private void configure(Map<String, Object> properties) {
+
+ producer = (EventPublisher) properties.get(PARAM_EVENT_STREAM_PRODUCER);
+
+ eventQueueCapacity =
+ (Integer) getProperty(properties, PARAM_EVENT_QUEUE_CAPACITY, DEFAULT_EVENT_QUEUE_CAPACITY);
+ eventStreamPublisherPoolSize =
+ (Integer) getProperty(properties, PARAM_EVENT_STREAM_PUBLISHER_POOL_SIZE, DEFAULT_EVENT_STREAM_PUBLISHER_POOL_SIZE);
+ }
+
+
+ public void setProducer(EventPublisher aProducer) {
+
+ producer = aProducer;
+ }
+
+ private Object getProperty(Map<String, Object> properties, String property, Object defaultValue) {
+
+ if(properties.containsKey(property)) {
+ return properties.get(property);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ @Override
+ public void shutdown() {
+
+ if(publisherPool != null) {
+ publisherPool.shutdown();
+
+ try {
+ publisherPool.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {}
+ }
+
+ if(producer != null) {
+
+ try {
+ producer.close();
+
+ } catch (Exception e) {
+ logger.error("Failed to stop event stream producer: " + e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void commitTransaction(ChampTransaction transaction) throws ChampTransactionException {
+
+ try {
+
+ // Commit the transaction.
+ transaction.commit();
+
+ } catch (ChampTransactionException e) {
+
+ logger.warn("Events associated with transaction " + transaction.id() + " not generated due to transaction commit failure.");
+
+ List<ChampEvent> enqueuedEvents = transaction.getEnqueuedEvents();
+ for(ChampEvent event : enqueuedEvents) {
+
+ logger.debug("Graph event " + event.toString() + " not published.");
+ }
+ throw e;
+ }
+
+ // Now that the transaction has been successfully committed, we need
+ // to log the events that were produced within that transaction's
+ // context.
+ List<ChampEvent> enqueuedEvents = transaction.getEnqueuedEvents();
+ for(ChampEvent event : enqueuedEvents) {
+ logEvent(event);
+ }
+ }
+
+ @Override
+ public void rollbackTransaction(ChampTransaction transaction) throws ChampTransactionException {
+
+ // Rollback the transaction.
+ transaction.rollback();
+ }
+
+ @Override
+ public ChampObject storeObject(ChampObject object) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException {
+ return storeObject(object, Optional.empty());
+ }
+
+ @Override
+ public ChampObject storeObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException {
+
+ ChampObject storedObject = executeStoreObject(object, transaction);
+
+ if(storedObject != null) {
+
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.STORE)
+ .entity(storedObject)
+ .build(),
+ transaction);
+ }
+
+ return storedObject;
+ }
+
+ @Override
+ public ChampObject replaceObject(ChampObject object)
+ throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException {
+
+ return replaceObject(object, Optional.empty());
+ }
+
+ @Override
+ public ChampObject replaceObject(ChampObject object, Optional<ChampTransaction> transaction)
+ throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException {
+
+ ChampObject replacedObject = executeReplaceObject(object, transaction);
+
+ if(replacedObject != null) {
+
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.REPLACE)
+ .entity(replacedObject)
+ .build(),
+ transaction);
+ }
+
+ return replacedObject;
+ }
+
+ @Override
+ public void deleteObject(Object key) throws ChampObjectNotExistsException, ChampTransactionException {
+ deleteObject(key, Optional.empty());
+ }
+
+ @Override
+ public void deleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException, ChampTransactionException {
+
+ // Retrieve the object that we are deleting before it's gone, so that we can
+ // report it to the event stream.
+ Optional<ChampObject> objectToDelete = Optional.empty();
+ try {
+ objectToDelete = retrieveObject(key, transaction);
+
+ } catch (ChampUnmarshallingException e) {
+ logger.error("Unable to generate delete object log: " + e.getMessage());
+ }
+
+ executeDeleteObject(key, transaction);
+
+ if(objectToDelete.isPresent()) {
+ // Update the event stream with the current operation.
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.DELETE)
+ .entity(objectToDelete.get())
+ .build(),
+ transaction);
+ }
+ }
+
+ @Override
+ public ChampRelationship storeRelationship(ChampRelationship relationship)
+ throws ChampUnmarshallingException,
+ ChampMarshallingException,
+ ChampObjectNotExistsException,
+ ChampSchemaViolationException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+ return storeRelationship(relationship, Optional.empty());
+ }
+
+ @Override
+ public ChampRelationship storeRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException,
+ ChampMarshallingException,
+ ChampObjectNotExistsException,
+ ChampSchemaViolationException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+
+ ChampRelationship storedRelationship = executeStoreRelationship(relationship, transaction);
+
+ if(storedRelationship != null) {
+
+ // Update the event stream with the current operation.
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.STORE)
+ .entity(storedRelationship)
+ .build(),
+ transaction);
+ }
+
+ return storedRelationship;
+ }
+
+ @Override
+ public ChampRelationship replaceRelationship(ChampRelationship relationship)
+ throws ChampUnmarshallingException,
+ ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+ return replaceRelationship(relationship, Optional.empty());
+ }
+
+ @Override
+ public ChampRelationship replaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException,
+ ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+
+ ChampRelationship replacedRelationship = executeReplaceRelationship(relationship, transaction);
+
+ if(replacedRelationship != null) {
+
+ // Update the event stream with the current operation.
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.REPLACE)
+ .entity(replacedRelationship)
+ .build(),
+ transaction);
+ }
+
+ return replacedRelationship;
+ }
+
+ @Override
+ public void deleteRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException, ChampTransactionException {
+ deleteRelationship(relationship, Optional.empty());
+ }
+
+ @Override
+ public void deleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampTransactionException {
+
+ executeDeleteRelationship(relationship, transaction);
+
+ // Update the event stream with the current operation.
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.DELETE)
+ .entity(relationship)
+ .build(),
+ transaction);
+ }
+
+ @Override
+ public ChampPartition storePartition(ChampPartition partition) throws ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
+ return storePartition(partition, Optional.empty());
+ }
+
+ @Override
+ public ChampPartition storePartition(ChampPartition partition, Optional<ChampTransaction> transaction) throws ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
+
+ ChampPartition storedPartition = executeStorePartition(partition, transaction);
+
+ if(storedPartition != null) {
+
+ // Update the event stream with the current operation.
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.STORE)
+ .entity(storedPartition)
+ .build(),
+ transaction);
+ }
+
+ return storedPartition;
+ }
+
+ @Override
+ public void deletePartition(ChampPartition graph) throws ChampTransactionException{
+ deletePartition(graph, Optional.empty());
+ }
+
+ @Override
+ public void deletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) throws ChampTransactionException {
+
+ executeDeletePartition(graph, transaction);
+
+ // Update the event stream with the current operation.
+ logOrEnqueueEvent(ChampEvent.builder()
+ .operation(ChampOperation.DELETE)
+ .entity(graph)
+ .build(),
+ transaction);
+ }
+
+ @Override
+ public void storeObjectIndex(ChampObjectIndex index) {
+
+ executeStoreObjectIndex(index);
+
+ // Update the event stream with the current operation.
+ logEvent(ChampEvent.builder()
+ .operation(ChampOperation.STORE)
+ .entity(index)
+ .build());
+ }
+
+
+ public void deleteObjectIndex(String indexName) throws ChampIndexNotExistsException {
+
+ // Retrieve the index that we are deleting before it's gone, so that we can
+ // report it to the event stream.
+ Optional<ChampObjectIndex> indexToDelete = retrieveObjectIndex(indexName);
+
+ executeDeleteObjectIndex(indexName);
+
+ if(indexToDelete.isPresent()) {
+ // Update the event stream with the current operation.
+ logEvent(ChampEvent.builder()
+ .operation(ChampOperation.DELETE)
+ .entity(indexToDelete.get())
+ .build());
+ }
+ }
+
+
+ public void storeRelationshipIndex(ChampRelationshipIndex index) {
+
+ executeStoreRelationshipIndex(index);
+
+ // Update the event stream with the current operation.
+ logEvent(ChampEvent.builder()
+ .operation(ChampOperation.STORE)
+ .entity(index)
+ .build());
+ }
+
+
+ public void deleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException {
+
+ // Retrieve the index that we are deleting before it's gone, so that we can
+ // report it to the event stream.
+ Optional<ChampRelationshipIndex> indexToDelete = retrieveRelationshipIndex(indexName);
+
+ executeDeleteRelationshipIndex(indexName);
+
+ if(indexToDelete.isPresent()) {
+ // Update the event stream with the current operation.
+ logEvent(ChampEvent.builder()
+ .operation(ChampOperation.DELETE)
+ .entity(indexToDelete.get())
+ .build());
+ }
+ }
+
+ private void logOrEnqueueEvent(ChampEvent event, Optional<ChampTransaction> transaction) {
+
+ if(!transaction.isPresent()) {
+ // Update the event stream with the current operation.
+ logEvent(event);
+ } else {
+
+ // when the TransactionID is present, add it to the event payload before logging/enqueing the event.
+ event.setDbTransactionId ( transaction.get ().id () );
+ transaction.get().logEvent(event);
+ }
+ }
+
+ /**
+ * Submits an event to be published to the event stream.
+ *
+ * @param anEvent - The event to be published.
+ */
+ public void logEvent(ChampEvent anEvent) {
+
+ if(eventQueue == null) {
+ return;
+ }
+
+ logger.info("Log champcore event with transaction id: " + anEvent.getTransactionId() + " to event bus");
+ if(logger.isDebugEnabled()) {
+ logger.debug("Event payload: " + anEvent.toString());
+ }
+
+ // Try to submit the event to be published to the event bus.
+ if(!eventQueue.offer(anEvent)) {
+ logger.error("Event could not be published to the event bus due to: Internal buffer capacity exceeded.");
+ }
+ }
+
+
+ /**
+ * This class implements the worker threads for our thread pool which are responsible for
+ * pulling the next outgoing event from the internal buffer and forwarding them to the event
+ * bus client.
+ * <p>
+ * Each publish operation is performed synchronously, so that the thread will only move on
+ * to the next available event once it has actually published the current event to the bus.
+ */
+ private class EventPublisherWorker implements Runnable {
+
+ /** Partition key to use when publishing events to the event stream. We WANT all events
+ * to go to a single partition, so we are just using a hard-coded key for every event. */
+ private static final String EVENTS_PARTITION_KEY = "champEventKey";
+
+
+ @Override
+ public void run() {
+
+ while(true) {
+
+ ChampEvent event = null;
+ try {
+
+ // Get the next event to be published from the queue.
+ event = eventQueue.take();
+
+ } catch (InterruptedException e) {
+
+ // Restore the interrupted status.
+ Thread.currentThread().interrupt();
+ }
+
+ // Try publishing the event to the event bus. This call will block
+ // until
+ try {
+ producer.sendSync(EVENTS_PARTITION_KEY, event.toJson());
+
+ } catch (Exception e) {
+
+ logger.error("Failed to publish event to event bus: " + e.getMessage());
+ }
+ }
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/ChampEvent.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/ChampEvent.java
new file mode 100644
index 0000000..46f1b61
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/ChampEvent.java
@@ -0,0 +1,213 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.event;
+
+
+import java.io.IOException;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+
+public class ChampEvent {
+
+ public enum ChampOperation {
+ STORE,
+ REPLACE,
+ DELETE
+ }
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ private ChampOperation operation;
+ private long timestamp;
+ private String transactionId = null;
+ private ChampObject vertex = null;
+ private ChampRelationship relationship = null;
+ private ChampPartition partition = null;
+ private ChampObjectIndex objectIndex = null;
+ private ChampRelationshipIndex relationshipIndex = null;
+ private String dbTransactionId = null;
+
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public ChampOperation getOperation() {
+ return operation;
+ }
+
+ public void setOperation(ChampOperation operation) {
+ this.operation = operation;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ @JsonProperty("transaction-id")
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public void setTransactionId(String transactionId) {
+ this.transactionId = transactionId;
+ }
+
+ public ChampObject getVertex() {
+ return vertex;
+ }
+
+ public void setVertex(ChampObject vertex) {
+ this.vertex = vertex;
+ }
+
+ public ChampRelationship getRelationship() {
+ return relationship;
+ }
+
+ public void setRelationship(ChampRelationship relationship) {
+ this.relationship = relationship;
+ }
+
+ public ChampPartition getPartition() {
+ return partition;
+ }
+
+ public void setPartition(ChampPartition partition) {
+ this.partition = partition;
+ }
+
+ public ChampObjectIndex getObjectIndex() {
+ return objectIndex;
+ }
+
+ public void setObjectIndex(ChampObjectIndex index) {
+ this.objectIndex = index;
+ }
+
+ public ChampRelationshipIndex getRelationshipIndex() {
+ return relationshipIndex;
+ }
+
+ public void setRelationshipIndex(ChampRelationshipIndex relationshipIndex) {
+ this.relationshipIndex = relationshipIndex;
+ }
+
+ @JsonProperty("database-transaction-id")
+ public String getDbTransactionId () { return dbTransactionId; }
+
+
+ public void setDbTransactionId ( String id ) { this.dbTransactionId = id; }
+
+
+
+ public String toJson() {
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(Include.NON_NULL);
+
+ try {
+ return mapper.writeValueAsString(this);
+ } catch (JsonProcessingException e) {
+ return "Unmarshallable: " + e.getMessage();
+ }
+ }
+
+ public static ChampEvent fromJson(String json) throws JsonParseException, JsonMappingException, IOException {
+
+ mapper.setSerializationInclusion(Include.NON_NULL);
+ return mapper.readValue(json, ChampEvent.class);
+ }
+ @Override
+ public String toString() {
+
+ return toJson();
+ }
+
+ public static class Builder {
+
+ ChampEvent event = null;
+
+
+ public Builder() {
+ event = new ChampEvent();
+ }
+
+ public Builder operation(ChampOperation operation) {
+ event.setOperation(operation);
+ return this;
+ }
+
+ public Builder entity(ChampObject entity) {
+ event.setVertex(entity);
+ return this;
+ }
+
+ public Builder entity(ChampRelationship relationship) {
+ event.relationship = relationship;
+ return this;
+ }
+
+ public Builder entity(ChampPartition partition) {
+ event.partition = partition;
+ return this;
+ }
+
+ public Builder entity(ChampObjectIndex index) {
+ event.objectIndex = index;
+ return this;
+ }
+
+ public Builder entity(ChampRelationshipIndex relationshipIndex) {
+ event.relationshipIndex = relationshipIndex;
+ return this;
+ }
+
+
+ public ChampEvent build() {
+
+ event.setTimestamp(System.currentTimeMillis());
+
+ // Set a unique transaction id on this event that can be used by downstream entities
+ // for log correlation.
+ event.setTransactionId(java.util.UUID.randomUUID().toString());
+
+ return event;
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampIndexNotExistsException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampIndexNotExistsException.java
new file mode 100644
index 0000000..e969ce5
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampIndexNotExistsException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+public final class ChampIndexNotExistsException extends Exception {
+
+ private static final long serialVersionUID = 1690478892404278379L;
+
+ public ChampIndexNotExistsException() {}
+
+ public ChampIndexNotExistsException(String message) {
+ super(message);
+ }
+
+ public ChampIndexNotExistsException(Throwable cause) {
+ super(cause);
+ }
+
+ public ChampIndexNotExistsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampMarshallingException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampMarshallingException.java
new file mode 100644
index 0000000..09ede7a
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampMarshallingException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+public final class ChampMarshallingException extends Exception {
+
+ private static final long serialVersionUID = 7962962670920382670L;
+
+ public ChampMarshallingException() {}
+
+ public ChampMarshallingException(String message) {
+ super(message);
+ }
+
+ public ChampMarshallingException(Throwable cause) {
+ super(cause);
+ }
+
+ public ChampMarshallingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampObjectNotExistsException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampObjectNotExistsException.java
new file mode 100644
index 0000000..cd63401
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampObjectNotExistsException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+public final class ChampObjectNotExistsException extends Exception {
+
+ private static final long serialVersionUID = -4365365939154593814L;
+
+ public ChampObjectNotExistsException() {}
+
+ public ChampObjectNotExistsException(String message) {
+ super(message);
+ }
+
+ public ChampObjectNotExistsException(Throwable cause) {
+ super(cause);
+ }
+
+ public ChampObjectNotExistsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampRelationshipNotExistsException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampRelationshipNotExistsException.java
new file mode 100644
index 0000000..4cdde58
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampRelationshipNotExistsException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+public final class ChampRelationshipNotExistsException extends Exception {
+
+ private static final long serialVersionUID = -3006050460369110202L;
+
+ public ChampRelationshipNotExistsException() {}
+
+ public ChampRelationshipNotExistsException(String message) {
+ super(message);
+ }
+
+ public ChampRelationshipNotExistsException(Throwable cause) {
+ super(cause);
+ }
+
+ public ChampRelationshipNotExistsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampSchemaViolationException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampSchemaViolationException.java
new file mode 100644
index 0000000..b234bc4
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampSchemaViolationException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+public final class ChampSchemaViolationException extends Exception {
+
+ private static final long serialVersionUID = -6650058224577965021L;
+
+ public ChampSchemaViolationException() {}
+
+ public ChampSchemaViolationException(String message) {
+ super(message);
+ }
+
+ public ChampSchemaViolationException(Throwable cause) {
+ super(cause);
+ }
+
+ public ChampSchemaViolationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampTransactionException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampTransactionException.java
new file mode 100644
index 0000000..17251b2
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampTransactionException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+public class ChampTransactionException extends Exception {
+
+ private static final long serialVersionUID = -5492385992668214838L;
+
+ public ChampTransactionException() {}
+
+ public ChampTransactionException(String message) {
+ super(message);
+ }
+
+ public ChampTransactionException(Throwable cause) {
+ super(cause);
+ }
+
+ public ChampTransactionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampUnmarshallingException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampUnmarshallingException.java
new file mode 100644
index 0000000..b8383d8
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampUnmarshallingException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+public final class ChampUnmarshallingException extends Exception {
+
+ private static final long serialVersionUID = 8162385108397238865L;
+
+ public ChampUnmarshallingException() {}
+
+ public ChampUnmarshallingException(String message) {
+ super(message);
+ }
+
+ public ChampUnmarshallingException(Throwable cause) {
+ super(cause);
+ }
+
+ public ChampUnmarshallingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractTinkerpopChampGraph.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractTinkerpopChampGraph.java
new file mode 100644
index 0000000..9a45e91
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractTinkerpopChampGraph.java
@@ -0,0 +1,1068 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.graph.impl;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.Vector;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.NoOpTinkerPopTransaction;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.partition.CreateChampPartitionable;
+import org.onap.aai.champcore.transform.TinkerpopChampformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public abstract class AbstractTinkerpopChampGraph extends AbstractValidatingChampGraph {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTinkerpopChampGraph.class);
+ private static final TinkerpopChampformer TINKERPOP_CHAMPFORMER = new TinkerpopChampformer();
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ private volatile AtomicBoolean isShutdown;
+
+ protected AbstractTinkerpopChampGraph(Map<String, Object> properties) {
+ super(properties);
+
+ isShutdown = new AtomicBoolean(false);
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+ }
+
+ private static final TinkerpopChampformer getChampformer() {
+ return TINKERPOP_CHAMPFORMER;
+ }
+
+ private static final ObjectMapper getObjectMapper() {
+ return OBJECT_MAPPER;
+ }
+
+ public abstract GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type);
+
+ public ChampTransaction openTransaction() {
+
+ return new TinkerpopTransaction(getGraph());
+ }
+
+ private Vertex writeVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
+ final Vertex vertex;
+
+ Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
+
+ if (object.getKey().isPresent()) {
+ final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
+
+ if (vertexIter.hasNext()) {
+ vertex = vertexIter.next();
+ } else throw new ChampObjectNotExistsException();
+ } else {
+ vertex = graphInstance.addVertex(object.getType());
+ }
+
+ for (Entry<String, Object> property : object.getProperties().entrySet()) {
+
+ if (property.getValue() instanceof List) {
+ for (Object subPropertyValue : (List<?>) property.getValue()) {
+ vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
+ }
+ } else if (property.getValue() instanceof Set) {
+ for (Object subPropertyValue : (Set<?>) property.getValue()) {
+ vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
+ }
+ } else {
+ vertex.property(property.getKey(), property.getValue());
+ }
+ }
+
+ return vertex;
+ }
+
+ private Vertex replaceVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
+ Vertex vertex;
+
+ Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
+
+ if (object.getKey().isPresent()) {
+ final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
+
+ if (vertexIter.hasNext()) {
+ vertex = vertexIter.next();
+ } else throw new ChampObjectNotExistsException();
+ } else {
+ throw new ChampObjectNotExistsException();
+ }
+
+ //clear all the existing properties
+ Iterator<VertexProperty<Object>> it = vertex.properties();
+ while (it.hasNext()) {
+ it.next().remove();
+ }
+
+ for (Entry<String, Object> property : object.getProperties().entrySet()) {
+
+ if (property.getValue() instanceof List) {
+ for (Object subPropertyValue : (List<?>) property.getValue()) {
+ vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
+ }
+ } else if (property.getValue() instanceof Set) {
+ for (Object subPropertyValue : (Set<?>) property.getValue()) {
+ vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
+ }
+ } else {
+ vertex.property(property.getKey(), property.getValue());
+ }
+ }
+
+ return vertex;
+ }
+
+ private Edge writeEdge(ChampRelationship relationship, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException {
+
+ final Vertex source = writeVertex(relationship.getSource(), transaction);
+ final Vertex target = writeVertex(relationship.getTarget(), transaction);
+ final Edge edge;
+
+ Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
+
+ if (relationship.getKey().isPresent()) {
+ final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
+
+ if (edgeIter.hasNext()) {
+ edge = edgeIter.next();
+ } else throw new ChampRelationshipNotExistsException();
+ } else {
+ edge = source.addEdge(relationship.getType(), target);
+ }
+
+ for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
+ edge.property(property.getKey(), property.getValue());
+ }
+
+ return edge;
+ }
+
+ private Edge replaceEdge(ChampRelationship relationship, ChampTransaction tx) throws ChampRelationshipNotExistsException, ChampMarshallingException {
+ final Edge edge;
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ if(!relationship.getSource().getKey().isPresent() || !relationship.getTarget().getKey().isPresent()){
+ throw new IllegalArgumentException("Invalid source/target");
+ }
+
+ if (relationship.getKey().isPresent()) {
+ final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
+
+
+ if (edgeIter.hasNext()) {
+ edge = edgeIter.next();
+ //validate if the source/target are the same as before. Throw error if not the same
+ if (!edge.outVertex().id().equals(relationship.getSource().getKey().get())
+ || !edge.inVertex().id().equals(relationship.getTarget().getKey().get())) {
+ throw new IllegalArgumentException("source/target can't be updated");
+ }
+
+ } else throw new ChampRelationshipNotExistsException();
+ } else {
+ throw new ChampRelationshipNotExistsException();
+ }
+
+ // clear all the existing properties
+ Iterator<Property<Object>> it = edge.properties();
+ while (it.hasNext()) {
+ it.next().remove();
+ }
+
+ for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
+ edge.property(property.getKey(), property.getValue());
+ }
+
+ return edge;
+ }
+
+
+ protected abstract Graph getGraph();
+
+
+
+ private Thread shutdownHook = new Thread() {
+ @Override
+ public void run() {
+ try {
+ shutdown();
+ } catch (IllegalStateException e) {
+ //Suppress, because shutdown() has already been called
+ }
+ }
+ };
+
+ protected boolean isShutdown() {
+ return isShutdown.get();
+ }
+
+ @Override
+ public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) throws ChampTransactionException {
+ return queryObjects(queryParams, Optional.empty());
+ }
+
+
+ @Override
+ public Stream<ChampObject> queryObjects(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ //If they provided the object key, do this the quick way rather than creating a traversal
+ if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString())) {
+
+ try {
+ final Optional<ChampObject> object =
+ retrieveObject(queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString()),
+ transaction);
+
+ if (object.isPresent()) {
+ return Stream.of(object.get());
+ } else {
+ return Stream.empty();
+ }
+ } catch (ChampUnmarshallingException e) {
+ LOGGER.warn("Failed to unmarshall object", e);
+ return Stream.empty();
+ }
+ }
+
+ final GraphTraversal<Vertex, Vertex> query = graphInstance.traversal().V();
+
+ for (Entry<String, Object> filter : queryParams.entrySet()) {
+ if (filter.getKey().equals(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
+ continue; //For performance reasons, the label is the last thing to be added
+ } else {
+ query.has(filter.getKey(), filter.getValue());
+ }
+ }
+
+ if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
+ hasLabel(query, queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString()));
+ }
+
+ final Iterator<ChampObject> objIter = new Iterator<ChampObject> () {
+
+ private ChampObject next;
+
+
+ @Override
+ public boolean hasNext() {
+ while (query.hasNext()) {
+ try {
+ next = getChampformer().unmarshallObject(query.next());
+ return true;
+ } catch (ChampUnmarshallingException e) {
+ LOGGER.warn("Failed to unmarshall tinkerpop vertex during query, returning partial results", e);
+ }
+ }
+
+ // If we auto-created the transaction, then commit it now, otherwise it is up to the
+ // caller to decide when and if to do the commit.
+ if(!transaction.isPresent()) {
+ try {
+ tx.commit(); //Danger ahead if this iterator is not completely consumed
+ //then the transaction cache will hold stale values
+ } catch (ChampTransactionException e) {
+ LOGGER.warn("Failed transaction commit due to: " + e.getMessage());
+ }
+
+ }
+
+ next = null;
+ return false;
+ }
+
+ @Override
+ public ChampObject next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+
+ return next;
+ }
+ };
+
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(objIter,
+ Spliterator.ORDERED | Spliterator.NONNULL),
+ false);
+ }
+
+ @Override
+ public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException, ChampTransactionException {
+ return retrieveObject(key, Optional.empty());
+ }
+
+ @Override
+ public Optional<ChampObject> retrieveObject(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ final Iterator<Vertex> vertices = graphInstance.vertices(key);
+ final Optional<ChampObject> optionalObject;
+
+ if (!vertices.hasNext()) {
+ optionalObject = Optional.empty();
+
+ } else {
+ optionalObject = Optional.of(getChampformer().unmarshallObject(vertices.next()));
+ }
+
+ // If we auto-created the transaction, then commit it now, otherwise it is up to the
+ // caller to decide when and if to do the commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+
+ return optionalObject;
+ }
+
+ @Override
+ public Stream<ChampRelationship> retrieveRelationships(ChampObject source) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
+ return retrieveRelationships(source, Optional.empty());
+ }
+
+ @Override
+ public Stream<ChampRelationship> retrieveRelationships(ChampObject source, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ final Vertex sourceVertex;
+
+ try {
+ sourceVertex = graphInstance.vertices(source.getKey().get()).next();
+
+ } catch (NoSuchElementException e) {
+
+ // If we auto-created the transaction, then try to roll it back now, otherwise it is
+ // up to the caller to decide when and if to do so.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ throw new ChampObjectNotExistsException();
+ }
+
+ final Iterator<Edge> edges = sourceVertex.edges(Direction.BOTH);
+ final Iterator<ChampRelationship> relIter = new Iterator<ChampRelationship> () {
+
+ private ChampRelationship next;
+
+ @Override
+ public boolean hasNext() {
+ while (edges.hasNext()) {
+ try {
+ next = getChampformer().unmarshallRelationship(edges.next());
+ return true;
+ } catch (ChampUnmarshallingException e) {
+ LOGGER.warn("Failed to unmarshall tinkerpop edge during query, returning partial results", e);
+ }
+ }
+
+ // If we auto-created the transaction, then commit it now, otherwise it is up to the
+ // caller to decide when and if to do the commit.
+ if(!transaction.isPresent()) {
+ try {
+ tx.commit(); //Danger ahead if this iterator is not completely
+ //consumed, then the transaction cache will be stale
+
+ } catch (ChampTransactionException e) {
+ LOGGER.warn("Failed transaction commit due to: " + e.getMessage());
+ }
+
+ }
+ next = null;
+ return false;
+ }
+
+ @Override
+ public ChampRelationship next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+
+ return next;
+ }
+ };
+
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ relIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
+ }
+
+
+ @Override
+ public ChampObject doStoreObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
+
+ ChampTransaction tx = null;
+
+ try {
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ tx = getOrCreateTransactionInstance(transaction);
+
+ // Now, store the object that we were supplied.
+ final Vertex vertex = writeVertex(object, tx);
+
+ // Only auto-commit this operation if we were NOT provided a transaction context,
+ // otherwise it is the caller's responsibility to commit the transaction when it
+ // is appropriate to do so.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+
+ // Marshal the resulting vertex into a ChampObject and return it to the caller.
+ return ChampObject.create()
+ .from(object)
+ .withKey(vertex.id())
+ .build();
+
+ } catch (ChampObjectNotExistsException e) {
+
+ // Something went wrong. If we auto-created the transaction, then try to roll it back
+ // now. If we were supplied a transaction context then it is the caller's responsibility
+ // to decide whether or not to roll it back.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ // Rethrow the exception.
+ throw e;
+ }
+ }
+
+ @Override
+ public ChampObject doReplaceObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
+
+ ChampTransaction tx = null;
+
+ try {
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ tx = getOrCreateTransactionInstance(transaction);
+
+ final Vertex vertex = replaceVertex(object, tx);
+
+ // Only auto-commit this operation if we were NOT provided a transaction context,
+ // otherwise it is the caller's responsibility to commit the transaction when it
+ // is appropriate to do so.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+
+ // Marshal the resulting vertex into a ChampObject and return it to the caller.
+ return ChampObject.create()
+ .from(object)
+ .withKey(vertex.id())
+ .build();
+
+ } catch (ChampObjectNotExistsException e) {
+
+ // Something went wrong. If we auto-created the transaction, then try to roll it back
+ // now. If we were supplied a transaction context then it is the caller's responsibility
+ // to decide whether or not to roll it back.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ // Rethrow the exception.
+ throw e;
+ }
+ }
+
+ @Override
+ public void executeDeleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ final Iterator<Vertex> vertex = graphInstance.vertices(key);
+
+ if (!vertex.hasNext()) {
+
+ // If we auto-created the transaction, then roll it back now, otherwise it
+ // is up to the caller to make that determination.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ throw new ChampObjectNotExistsException();
+ }
+
+ // Remove the vertex.
+ vertex.next().remove();
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+ }
+
+ @Override
+ public ChampRelationship doStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException,
+ ChampObjectNotExistsException,
+ ChampRelationshipNotExistsException,
+ ChampMarshallingException,
+ ChampTransactionException {
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ try {
+
+ // Store the edge in the graph.
+ final Edge edge = writeEdge(relationship, tx);
+
+ // Unmarshal the stored edge into a ChampRelationship object
+ ChampRelationship storedRelationship = getChampformer().unmarshallRelationship(edge);
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+
+ // Finally, return the result to the caller.
+ return storedRelationship;
+
+ } catch (ChampObjectNotExistsException |
+ ChampRelationshipNotExistsException |
+ ChampUnmarshallingException |
+ ChampMarshallingException e) {
+
+ // If we auto-create the transaction, then try to roll it back, otherwise
+ // it is up to the caller to decide when and if to do so.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+ throw e;
+ }
+ }
+
+
+ @Override
+ public ChampRelationship doReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException,
+ ChampRelationshipNotExistsException,
+ ChampMarshallingException,
+ ChampTransactionException {
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ try {
+ final Edge edge = replaceEdge(relationship, tx);
+
+ ChampRelationship unmarshalledRelationship = getChampformer().unmarshallRelationship(edge);
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+
+ return unmarshalledRelationship;
+
+ } catch ( ChampRelationshipNotExistsException | ChampUnmarshallingException | ChampMarshallingException e) {
+
+ // it is up to the caller to decide when and if to do so.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ throw e;
+ }
+ }
+
+ @Override
+ public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) throws ChampTransactionException {
+ return queryRelationships(queryParams, Optional.empty());
+ }
+
+ @Override
+ public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ // If they provided the relationship key, do this the quick way rather than creating a traversal
+ if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString())) {
+ try {
+ final Optional<ChampRelationship> relationship = retrieveRelationship(queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString()),
+ Optional.of(tx));
+
+ if (relationship.isPresent()) {
+ return Stream.of(relationship.get());
+
+ } else {
+ return Stream.empty();
+ }
+ } catch (ChampUnmarshallingException e) {
+
+ LOGGER.warn("Failed to unmarshall relationship", e);
+ return Stream.empty();
+ }
+ }
+
+ final GraphTraversal<Edge, Edge> query = graphInstance.traversal().E();
+
+ for (Entry<String, Object> filter : queryParams.entrySet()) {
+ if (filter.getKey().equals(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
+ continue; //Add the label last for performance reasons
+ } else {
+ query.has(filter.getKey(), filter.getValue());
+ }
+ }
+
+ if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
+ hasLabel(query, queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString()));
+ }
+
+ final Iterator<ChampRelationship> objIter = new Iterator<ChampRelationship> () {
+
+ private ChampRelationship next;
+
+ @Override
+ public boolean hasNext() {
+ while (query.hasNext()) {
+ try {
+ next = getChampformer().unmarshallRelationship(query.next());
+ return true;
+ } catch (ChampUnmarshallingException e) {
+ LOGGER.warn("Failed to unmarshall tinkerpop vertex during query, returning partial results", e);
+ }
+ }
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ try {
+ tx.commit(); //Danger ahead if this iterator is not completely
+ //consumed, then the transaction cache will be stale
+
+ } catch (ChampTransactionException e) {
+ LOGGER.warn("Failed transaction commit due to " + e.getMessage());
+ }
+
+ }
+
+ next = null;
+ return false;
+ }
+
+ @Override
+ public ChampRelationship next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+
+ return next;
+ }
+ };
+
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ objIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
+ }
+
+ @Override
+ public Optional<ChampRelationship> retrieveRelationship(Object key)
+ throws ChampUnmarshallingException, ChampTransactionException {
+ return retrieveRelationship(key, Optional.empty());
+ }
+
+ @Override
+ public Optional<ChampRelationship> retrieveRelationship(Object key, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ final Iterator<Edge> edge = graphInstance.edges(key);
+ final Optional<ChampRelationship> optionalRelationship;
+
+ if (!edge.hasNext()) {
+ optionalRelationship = Optional.empty();
+ } else {
+ optionalRelationship = Optional.of(getChampformer().unmarshallRelationship(edge.next()));
+ }
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+
+ return optionalRelationship;
+ }
+
+ @Override
+ public void executeDeleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ if (!relationship.getKey().isPresent()) {
+ throw new IllegalArgumentException("Key must be provided when deleting a relationship");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ final Iterator<Edge> edge = graphInstance.edges(relationship.getKey().get());
+
+ if (!edge.hasNext()) {
+
+ // If we auto-created the transaction, then try to roll it back now, otherwise it
+ // is up to the caller to decide if and when to do so.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ throw new ChampRelationshipNotExistsException();
+ }
+
+ edge.next().remove();
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+ }
+
+
+ @Override
+ public ChampPartition doStorePartition(ChampPartition submittedPartition, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ try {
+ final HashMap<ChampObject, ChampObject> objectsWithKeys = new HashMap<ChampObject, ChampObject> ();
+ final CreateChampPartitionable storedPartition = ChampPartition.create();
+
+ for (ChampObject champObject : submittedPartition.getChampObjects()) {
+ final Vertex vertex = writeVertex(champObject, tx);
+ objectsWithKeys.put(champObject, ChampObject.create()
+ .from(champObject)
+ .withKey(vertex.id())
+ .build());
+ }
+
+ for (ChampRelationship champRelationship : submittedPartition.getChampRelationships()) {
+
+ if (!objectsWithKeys.containsKey(champRelationship.getSource())) {
+ final Vertex vertex = writeVertex(champRelationship.getSource(), tx);
+
+ objectsWithKeys.put(champRelationship.getSource(), ChampObject.create()
+ .from(champRelationship.getSource())
+ .withKey(vertex.id())
+ .build());
+ }
+
+ if (!objectsWithKeys.containsKey(champRelationship.getTarget())) {
+ final Vertex vertex = writeVertex(champRelationship.getTarget(), tx);
+
+ objectsWithKeys.put(champRelationship.getTarget(), ChampObject.create()
+ .from(champRelationship.getTarget())
+ .withKey(vertex.id())
+ .build());
+ }
+
+ final ChampRelationship.Builder relWithKeysBuilder = new ChampRelationship.Builder(objectsWithKeys.get(champRelationship.getSource()),
+ objectsWithKeys.get(champRelationship.getTarget()),
+ champRelationship.getType());
+
+ if (champRelationship.getKey().isPresent()) {
+ relWithKeysBuilder.key(champRelationship.getKey().get());
+ }
+
+ relWithKeysBuilder.properties(champRelationship.getProperties());
+
+ final Edge edge = writeEdge(relWithKeysBuilder.build(), tx);
+
+ storedPartition.withRelationship(ChampRelationship.create()
+ .from(champRelationship)
+ .withKey(edge.id())
+ .build());
+ }
+
+ for (ChampObject object : objectsWithKeys.values()) {
+ storedPartition.withObject(object);
+ }
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+
+ return storedPartition.build();
+
+ } catch (ChampObjectNotExistsException | ChampMarshallingException e) {
+
+ // If we auto-created the transaction, then try to roll it back now, otherwise it
+ // is up to the caller to decide if and when to do so.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ throw e;
+ }
+ }
+
+ @Override
+ public void executeDeletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) throws ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ ChampTransaction tx = getOrCreateTransactionInstance(transaction);
+
+ // Use the graph instance associated with our transaction.
+ Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
+
+ for (ChampObject champObject : graph.getChampObjects()) {
+ try {
+ final Object vertexId = champObject.getKey().get();
+ final Iterator<Vertex> vertex = graphInstance.vertices(vertexId);
+
+ if (vertex.hasNext()) {
+ vertex.next().remove();
+ }
+ } catch (NoSuchElementException e) {
+
+ // If we auto-created the transaction, then try to roll it back now, otherwise it
+ // is up to the caller to decide if and when to do so.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ throw new IllegalArgumentException("Must pass a key to delete an object");
+ }
+ }
+
+ for (ChampRelationship champRelationship : graph.getChampRelationships()) {
+ try {
+ final Iterator<Edge> edge = graphInstance.edges(champRelationship.getKey().get());
+
+ if (edge.hasNext()) {
+ edge.next().remove();
+ }
+ } catch (NoSuchElementException e) {
+
+ // If we auto-created the transaction, then try to roll it back now, otherwise it
+ // is up to the caller to decide if and when to do so.
+ if(!transaction.isPresent()) {
+ tx.rollback();
+ }
+
+ throw new IllegalArgumentException("Must pass a key to delete a relationship");
+ }
+ }
+
+ // If we auto-created the transaction, then commit it now, otherwise it
+ // is up to the caller to decide if and when to commit.
+ if(!transaction.isPresent()) {
+ tx.commit();
+ }
+ }
+
+ @Override
+ public void shutdown() {
+
+ if (isShutdown.compareAndSet(false, true)) {
+ super.shutdown();
+ try {
+ getGraph().close();
+ } catch (Throwable t) {
+ LOGGER.error("Exception while shutting down graph", t);
+ }
+ } else {
+ throw new IllegalStateException("Cannot call shutdown() after shutdown() was already initiated");
+ }
+ }
+
+ @Override
+ public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException {
+ if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated");
+
+ if (getGraph().features().graph().variables().supportsVariables()) {
+ try {
+ getGraph().variables().set("schema", getObjectMapper().writeValueAsBytes(schema));
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ super.storeSchema(schema);
+ }
+ }
+
+ @Override
+ public ChampSchema retrieveSchema() {
+ if (isShutdown()) throw new IllegalStateException("Cannot call retrieveSchema() after shutdown has been initiated");
+
+ if (getGraph().features().graph().variables().supportsVariables()) {
+ final Optional<byte[]> schema = getGraph().variables().get("schema");
+
+ if (schema.isPresent()) {
+ try {
+ return getObjectMapper().readValue(schema.get(), ChampSchema.class);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ return super.retrieveSchema();
+ }
+
+ @Override
+ public void deleteSchema() {
+ if (isShutdown()) throw new IllegalStateException("Cannot call deleteSchema() after shutdown has been initiated");
+
+ if (getGraph().features().graph().variables().supportsVariables()) {
+ getGraph().variables().remove("schema");
+ } else {
+ super.deleteSchema();
+ }
+ }
+
+ public ChampTransaction getOrCreateTransactionInstance(Optional<ChampTransaction> transaction) {
+
+ ChampTransaction tx = null;
+
+ // If we were not provided a transaction object then automatically open a transaction
+ // now.
+ if(!transaction.isPresent()) {
+
+ tx = new TinkerpopTransaction(getGraph());
+
+ } else {
+ tx = transaction.get();
+ }
+
+ return tx;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractValidatingChampGraph.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractValidatingChampGraph.java
new file mode 100644
index 0000000..4568bc3
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/AbstractValidatingChampGraph.java
@@ -0,0 +1,293 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.graph.impl;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.event.AbstractLoggingChampGraph;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.schema.ChampSchemaEnforcer;
+
+public abstract class AbstractValidatingChampGraph extends AbstractLoggingChampGraph {
+
+ private ChampSchema schema = ChampSchema.emptySchema();
+
+ protected abstract ChampSchemaEnforcer getSchemaEnforcer();
+ protected abstract boolean isShutdown();
+
+ /**
+ * Updates an existing vertex in the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ * <p>
+ *
+ * @param object - The vertex to be updated in the graph data store.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The updated vertex, marshaled as a {@link ChampObject}
+ *
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshalled into the backend representation
+ * @throws ChampObjectNotExistsException - If {@link org.onap.aai.champcore.model.ChampObject#getKey}
+ * is not present or object not found in the graph
+ */
+ protected abstract ChampObject doReplaceObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException, ChampTransactionException;
+
+ /**
+ * Creates or updates a vertex in the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param object - The vertex to be stored in the graph data store.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The vertex which was created, marshaled as a {@link ChampObject}
+ *
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshaled into the back end representation
+ * @throws ChampObjectNotExistsException - If {@link org.onap.aai.champcore.model.ChampObject#getKey}
+ * is not present or object not found in the graph
+ */
+ protected abstract ChampObject doStoreObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException;
+
+ /**
+ * Replaces an edge in the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The edge to be replaced in the graph data store.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The edge as it was replaced, marshaled as a {@link ChampRelationship}
+ *
+ * @throws ChampUnmarshallingException - If the edge which was created could not be
+ * unmarshaled into a ChampObject
+ * @throws ChampRelationshipNotExistsException - If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent()
+ * but the object cannot be found in the graph
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshaled into the back end representation
+ */
+ protected abstract ChampRelationship doReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampRelationshipNotExistsException, ChampMarshallingException, ChampTransactionException;
+
+ /**
+ * Creates or updates a relationship in the graph data store.
+ * <p>
+ * If a transaction context is not provided, then a transaction will be automatically
+ * created and committed for this operation only, otherwise, the supplied transaction
+ * will be used and it will be up to the caller to commit the transaction at its
+ * discretion.
+ *
+ * @param relationship - The relationship to be stored in the graph data store.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The relationship that was stored.
+ *
+ * @throws ChampUnmarshallingException - If the edge which was created could not be
+ * unmarshalled into a ChampObject
+ * @throws ChampObjectNotExistsException - If {@link org.onap.aai.champcore.model.ChampObject#getKey}
+ * is not present or object not found in the graph
+ * @throws ChampRelationshipNotExistsException - If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent()
+ * but the object cannot be found in the graph
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshalled into the backend representation
+ */
+ protected abstract ChampRelationship doStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException, ChampTransactionException;
+
+ /**
+ * Creates or updates a partition in the graph data store.
+ *
+ * @param partition - The partition to be stored in the graph data store.
+ * @param transaction - Optional transaction context to perform the operation in.
+ *
+ * @return - The partition that was stored.
+ *
+ * @throws ChampRelationshipNotExistsException - If {@link org.onap.aai.champcore.model.ChampRelationship#getKey}.isPresent()
+ * but the object cannot be found in the graph
+ * @throws ChampMarshallingException - If the {@code relationship} is not able to be
+ * marshalled into the backend representation
+ * @throws ChampObjectNotExistsException - If {@link org.onap.aai.champcore.model.ChampObject#getKey}
+ * is not present or object not found in the graph
+ */
+ protected abstract ChampPartition doStorePartition(ChampPartition partition, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException;
+
+ protected AbstractValidatingChampGraph(Map<String, Object> properties) {
+ super(properties);
+ }
+
+ @Override
+ public ChampObject executeStoreObject(ChampObject object, Optional<ChampTransaction> transaction)
+ throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ validate(object);
+
+ return doStoreObject(object, transaction);
+ }
+
+
+ @Override
+ public ChampObject executeReplaceObject(ChampObject object, Optional<ChampTransaction> transaction)
+ throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ validate(object);
+
+ return doReplaceObject(object, transaction);
+ }
+
+ @Override
+ public ChampRelationship executeStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException, ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ validate(relationship);
+
+ return doStoreRelationship(relationship, transaction);
+ }
+
+ @Override
+ public ChampRelationship executeReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException, ChampMarshallingException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ validate(relationship);
+
+ return doReplaceRelationship(relationship, transaction);
+ }
+
+ @Override
+ public ChampPartition executeStorePartition(ChampPartition partition, Optional<ChampTransaction> transaction) throws ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
+
+ if (isShutdown()) {
+ throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
+ }
+
+ validate(partition);
+
+ return doStorePartition(partition, transaction);
+ }
+
+ protected void validate(ChampObject object) throws ChampSchemaViolationException {
+ final Optional<ChampObjectConstraint> objectConstraint = retrieveSchema().getObjectConstraint(object.getType());
+
+ if (objectConstraint.isPresent()) getSchemaEnforcer().validate(object, objectConstraint.get());
+ }
+
+ protected void validate(ChampRelationship relationship) throws ChampSchemaViolationException {
+ final ChampSchema graphSchema = retrieveSchema();
+ final Optional<ChampRelationshipConstraint> relationshipConstraint = graphSchema.getRelationshipConstraint(relationship.getType());
+ final Optional<ChampObjectConstraint> sourceObjConstraint = graphSchema.getObjectConstraint(relationship.getSource().getType());
+ final Optional<ChampObjectConstraint> targetObjConstraint = graphSchema.getObjectConstraint(relationship.getTarget().getType());
+
+ if (relationshipConstraint.isPresent()) getSchemaEnforcer().validate(relationship, relationshipConstraint.get());
+ if (sourceObjConstraint.isPresent()) getSchemaEnforcer().validate(relationship.getSource(), sourceObjConstraint.get());
+ if (targetObjConstraint.isPresent()) getSchemaEnforcer().validate(relationship.getTarget(), targetObjConstraint.get());
+ }
+
+ protected void validate(ChampPartition partition) throws ChampSchemaViolationException {
+ for (ChampObject object : partition.getChampObjects()) {
+ validate(object);
+ }
+
+ for (ChampRelationship relationship : partition.getChampRelationships()) {
+ validate(relationship);
+ }
+ }
+
+ @Override
+ public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException {
+ if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated");
+
+ this.schema = schema;
+ }
+
+ @Override
+ public ChampSchema retrieveSchema() {
+ if (isShutdown()) throw new IllegalStateException("Cannot call retrieveSchema() after shutdown has been initiated");
+
+ return schema;
+ }
+
+ @Override
+ public void updateSchema(ChampObjectConstraint objectConstraint) throws ChampSchemaViolationException {
+ if (isShutdown()) throw new IllegalStateException("Cannot call updateSchema() after shutdown has been initiated");
+
+ final ChampSchema currentSchema = retrieveSchema();
+ final ChampSchema updatedSchema = new ChampSchema.Builder(currentSchema)
+ .constraint(objectConstraint)
+ .build();
+
+ storeSchema(updatedSchema);
+ }
+
+ @Override
+ public void updateSchema(ChampRelationshipConstraint relationshipConstraint) throws ChampSchemaViolationException {
+ if (isShutdown()) throw new IllegalStateException("Cannot call updateSchema() after shutdown has been initiated");
+
+ final ChampSchema currentSchema = retrieveSchema();
+ final ChampSchema updatedSchema = new ChampSchema.Builder(currentSchema)
+ .constraint(relationshipConstraint)
+ .build();
+
+ storeSchema(updatedSchema);
+ }
+
+ @Override
+ public void deleteSchema() {
+ if (isShutdown()) throw new IllegalStateException("Cannot call deleteSchema() after shutdown has been initiated");
+ this.schema = ChampSchema.emptySchema();
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/ChampAPIImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/ChampAPIImpl.java
new file mode 100644
index 0000000..607ba78
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/ChampAPIImpl.java
@@ -0,0 +1,88 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.graph.impl;
+
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChampAPIImpl implements ChampAPI {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ChampAPIImpl.class);
+
+ private final AtomicBoolean shutdown;
+ private final String type;
+ private final ConcurrentHashMap<String, ChampGraph> graphs;
+
+ public ChampAPIImpl(String type) {
+ this.type = type;
+ this.graphs = new ConcurrentHashMap<String, ChampGraph> ();
+ this.shutdown = new AtomicBoolean(false);
+ }
+
+ private ConcurrentHashMap<String, ChampGraph> getGraphs() {
+ return graphs;
+ }
+
+ @Override
+ public ChampGraph getGraph(String graphName) {
+ if (shutdown.get()) {
+ throw new IllegalStateException("Cannot call getGraph() after shutdown() has been initiated");
+ }
+
+ if (getGraphs().containsKey(graphName)) {
+ return getGraphs().get(graphName);
+ }
+
+ // At this point, we know a graph with this name doesn't exist. Create and return it.
+ final ChampGraph graph = new InMemoryChampGraphImpl.Builder().build();
+ graphs.put(graphName, graph);
+ return graph;
+ }
+
+ @Override
+ public void shutdown() {
+ if (shutdown.compareAndSet(false, true)) {
+ for (Entry<String, ChampGraph> graphEntry : graphs.entrySet()) {
+ LOGGER.info("Shutting down graph {}", graphEntry.getKey());
+
+ try {
+ graphEntry.getValue().shutdown();
+ LOGGER.info("Graph {} shutdown successfully", graphEntry.getKey());
+ } catch (Throwable t) {
+ LOGGER.warn("Caught exception while shutting down graph " + graphEntry.getKey(), t);
+ }
+ }
+ }
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/InMemoryChampGraphImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/InMemoryChampGraphImpl.java
new file mode 100644
index 0000000..5773505
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/InMemoryChampGraphImpl.java
@@ -0,0 +1,209 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.graph.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.onap.aai.champcore.ChampCapabilities;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.NoOpTinkerPopTransaction;
+import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+import org.onap.aai.champcore.schema.ChampSchemaEnforcer;
+import org.onap.aai.champcore.schema.DefaultChampSchemaEnforcer;
+
+public final class InMemoryChampGraphImpl extends AbstractTinkerpopChampGraph {
+
+ private static final ChampCapabilities CAPABILITIES = new ChampCapabilities() {
+
+ @Override
+ public boolean canDeleteObjectIndices() {
+ return true;
+ }
+
+ @Override
+ public boolean canDeleteRelationshipIndices() {
+ return true;
+ }
+ };
+
+ private final ConcurrentHashMap<String, ChampObjectIndex> objectIndices;
+ private final ConcurrentHashMap<String, ChampRelationshipIndex> relationshipIndices;
+
+ private final ChampSchemaEnforcer schemaEnforcer;
+ private final TinkerGraph graph;
+
+ private InMemoryChampGraphImpl(Builder builder) {
+ super(builder.graphConfiguration);
+ this.graph = TinkerGraph.open();
+
+ this.objectIndices = new ConcurrentHashMap<String, ChampObjectIndex> ();
+ this.relationshipIndices = new ConcurrentHashMap<String, ChampRelationshipIndex> ();
+
+ this.schemaEnforcer = builder.schemaEnforcer;
+ }
+
+ @Override
+ public ChampTransaction getOrCreateTransactionInstance(Optional<ChampTransaction> transaction) {
+
+ return new NoOpTinkerPopTransaction(getGraph());
+
+ }
+
+ public static class Builder {
+ private final Map<String, Object> graphConfiguration = new HashMap<String, Object> ();
+ private ChampSchemaEnforcer schemaEnforcer = new DefaultChampSchemaEnforcer();
+
+ public Builder() {}
+
+ public Builder schemaEnforcer(ChampSchemaEnforcer schemaEnforcer) {
+ this.schemaEnforcer = schemaEnforcer;
+ return this;
+ }
+
+ public Builder properties(Map<String, Object> properties) {
+
+ this.graphConfiguration.putAll(properties);
+ return this;
+ }
+
+ public Builder property(String path, Object value) {
+
+ graphConfiguration.put(path, value);
+ return this;
+ }
+
+ public InMemoryChampGraphImpl build() {
+ return new InMemoryChampGraphImpl(this);
+ }
+ }
+
+ protected ChampSchemaEnforcer getSchemaEnforcer() {
+ return schemaEnforcer;
+ }
+
+ @Override
+ protected TinkerGraph getGraph() {
+ return graph;
+ }
+
+
+ private ConcurrentHashMap<String, ChampObjectIndex> getObjectIndices() {
+ return objectIndices;
+ }
+
+ private ConcurrentHashMap<String, ChampRelationshipIndex> getRelationshipIndices() {
+ return relationshipIndices;
+ }
+
+ @Override
+ public void executeStoreObjectIndex(ChampObjectIndex index) {
+
+ if (isShutdown()) throw new IllegalStateException("Cannot call storeObjectIndex() after shutdown has been initiated");
+
+ getGraph().createIndex(index.getField().getName(), Vertex.class);
+ getObjectIndices().put(index.getName(), index);
+ }
+
+ @Override
+ public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName) {
+ if (isShutdown()) throw new IllegalStateException("Cannot call retrieveObjectIndex() after shutdown has been initiated");
+
+ if (getObjectIndices().containsKey(indexName))
+ return Optional.of(getObjectIndices().get(indexName));
+
+ return Optional.empty();
+ }
+
+ @Override
+ public Stream<ChampObjectIndex> retrieveObjectIndices() {
+ if (isShutdown()) throw new IllegalStateException("Cannot call retrieveObjectIndices() after shutdown has been initiated");
+
+ return getObjectIndices().values().stream();
+ }
+
+ public void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException {
+ if (isShutdown()) throw new IllegalStateException("Cannot call deleteObjectIndex() after shutdown has been initiated");
+
+ final ChampObjectIndex objectIndex = getObjectIndices().remove(indexName);
+
+ if (objectIndex == null) throw new ChampIndexNotExistsException();
+
+ getGraph().dropIndex(objectIndex.getField().getName(), Vertex.class);
+ }
+
+ public void executeStoreRelationshipIndex(ChampRelationshipIndex index) {
+ if (isShutdown()) throw new IllegalStateException("Cannot call storeRelationshipIndex() after shutdown has been initiated");
+
+ getGraph().createIndex(index.getField().getName(), Edge.class);
+ getRelationshipIndices().put(index.getName(), index);
+ }
+
+ @Override
+ public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName) {
+ if (isShutdown()) throw new IllegalStateException("Cannot call retrieveRelationshipIndex() after shutdown has been initiated");
+
+ if (getRelationshipIndices().containsKey(indexName)) {
+ return Optional.of(getRelationshipIndices().get(indexName));
+ }
+
+ return Optional.empty();
+ }
+
+ @Override
+ public Stream<ChampRelationshipIndex> retrieveRelationshipIndices() {
+ if (isShutdown()) throw new IllegalStateException("Cannot call retrieveRelationshipIndices() after shutdown has been initiated");
+
+ return getRelationshipIndices().values().stream();
+ }
+
+ public void executeDeleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException {
+ if (isShutdown()) throw new IllegalStateException("Cannot call deleteRelationshipIndex() after shutdown has been initiated");
+
+ final ChampRelationshipIndex relationshipIndex = getRelationshipIndices().remove(indexName);
+
+ if (relationshipIndex == null) throw new ChampIndexNotExistsException();
+
+ getGraph().dropIndex(relationshipIndex.getField().getName(), Edge.class);
+ }
+
+ @Override
+ public ChampCapabilities capabilities() {
+ return CAPABILITIES;
+ }
+
+ @Override
+ public GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type) {
+ return query.hasLabel((String)type, (String)type);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/TinkerpopTransaction.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/TinkerpopTransaction.java
new file mode 100644
index 0000000..6ffeab7
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/TinkerpopTransaction.java
@@ -0,0 +1,164 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.graph.impl;
+
+import java.util.UUID;
+
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TinkerpopTransaction extends ChampTransaction {
+
+ private static final int COMMIT_RETRY_COUNT = 3;
+
+ /** Threaded Tinkerpop transaction. */
+ protected Graph threadedTransaction;
+
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TinkerpopTransaction.class);
+
+ protected TinkerpopTransaction() { }
+
+
+ /**
+ * Creates a new transaction instance.
+ *
+ * @param aGraphInstance - Instance of the graph to request the transaction from.
+ */
+ public TinkerpopTransaction(Graph aGraphInstance) {
+ super();
+
+ if(!aGraphInstance.features().graph().supportsTransactions()) {
+ throw new UnsupportedOperationException();
+ }
+
+ // Request a threaded transaction object from the graph.
+ this.threadedTransaction = aGraphInstance.tx().createThreadedTx();
+
+ LOGGER.info("Open transaction - id: " + id);
+ }
+
+ @Override
+ public String id() {
+ return id.toString();
+ }
+
+ public Graph getGraphInstance() {
+ return threadedTransaction;
+ }
+
+ @Override
+ public void commit() throws ChampTransactionException {
+
+ LOGGER.debug("Commiting transaction - " + id);
+
+ final long initialBackoff = (int) (Math.random() * 50);
+
+ // If something goes wrong, we will retry a couple of times before
+ // giving up.
+ for (int i = 0; i < COMMIT_RETRY_COUNT; i++) {
+
+ try {
+
+ // Do the commit.
+ threadedTransaction.tx().commit();
+ LOGGER.info("Committed transaction - id: " + id);
+ return;
+
+ } catch (Throwable e) {
+
+ LOGGER.debug("Transaction " + id + " failed to commit due to: " + e.getMessage());
+
+ // Have we used up all of our retries?
+ if (i == COMMIT_RETRY_COUNT - 1) {
+
+ LOGGER.error("Maxed out commit attempt retries, client must handle exception and retry", e);
+ threadedTransaction.tx().rollback();
+ throw new ChampTransactionException(e);
+ }
+
+ // Calculate how long we will wait before retrying...
+ final long backoff = (long) Math.pow(2, i) * initialBackoff;
+ LOGGER.warn("Caught exception while retrying transaction commit, retrying in " + backoff + " ms");
+
+ // ...and sleep before trying the commit again.
+ try {
+ Thread.sleep(backoff);
+
+ } catch (InterruptedException ie) {
+
+ LOGGER.info("Interrupted while backing off on transaction commit");
+ Thread.interrupted();
+ return;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void rollback() throws ChampTransactionException {
+
+ long initialBackoff = (int) (Math.random() * 50);
+
+
+ // If something goes wrong, we will retry a couple of times before
+ // giving up.
+ for (int i = 0; i < COMMIT_RETRY_COUNT; i++) {
+
+ try {
+
+ threadedTransaction.tx().rollback();
+ LOGGER.info("Rolled back transaction - id: " + id);
+ return;
+
+ } catch (Throwable e) {
+
+ LOGGER.debug("Transaction " + id + " failed to roll back due to: " + e.getMessage());
+
+ // Have we used up all of our retries?
+ if (i == COMMIT_RETRY_COUNT - 1) {
+
+ LOGGER.error("Maxed out rollback attempt retries, client must handle exception and retry", e);
+ throw new ChampTransactionException(e);
+ }
+
+ // Calculate how long we will wait before retrying...
+ final long backoff = (long) Math.pow(2, i) * initialBackoff;
+ LOGGER.warn("Caught exception while retrying transaction roll back, retrying in " + backoff + " ms");
+
+ // ...and sleep before trying the commit again.
+ try {
+ Thread.sleep(backoff);
+
+ } catch (InterruptedException ie) {
+
+ LOGGER.info("Interrupted while backing off on transaction rollback");
+ Thread.interrupted();
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Exporter.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Exporter.java
new file mode 100644
index 0000000..ddea9ec
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Exporter.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.ie;
+
+import java.io.OutputStream;
+
+import org.onap.aai.champcore.ChampGraph;
+
+public interface Exporter {
+
+ public void exportData(ChampGraph graph, OutputStream os);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/GraphMLImporterExporter.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/GraphMLImporterExporter.java
new file mode 100644
index 0000000..71292ce
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/GraphMLImporterExporter.java
@@ -0,0 +1,471 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.ie;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class GraphMLImporterExporter implements Importer, Exporter {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GraphMLImporterExporter.class);
+
+ private static class GraphMLKey {
+ private final String id;
+ private final String attrName;
+ private final String attrType;
+
+ public GraphMLKey(String id, String attrName, Class<?> attrType) {
+ this.id = id;
+ this.attrName = attrName;
+
+ if (attrType.equals(Boolean.class)) {
+ this.attrType = "boolean";
+ } else if (attrType.equals(Integer.class)) {
+ this.attrType = "int";
+ } else if (attrType.equals(Long.class)) {
+ this.attrType = "long";
+ } else if (attrType.equals(Float.class)) {
+ this.attrType = "float";
+ } else if (attrType.equals(Double.class)) {
+ this.attrType = "double";
+ } else if (attrType.equals(String.class)) {
+ this.attrType = "string";
+ } else {
+ throw new RuntimeException("Cannot handle type " + attrType + " in GraphML");
+ }
+ }
+ }
+
+ public void importData(ChampAPI api, InputStream is) {
+
+ try {
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ final DocumentBuilder builder = factory.newDocumentBuilder();
+ final InputSource inputSource = new InputSource(is);
+ final Document doc = builder.parse(inputSource);
+
+ final Map<String, Map<String, String>> nodePropertyDefinitions = new HashMap<String, Map<String, String>> ();
+ final Map<String, Map<String, String>> edgePropertyDefinitions = new HashMap<String, Map<String, String>> ();
+ final Set<Map<String, String>> nodeDefaults = new HashSet<Map<String, String>> ();
+ final Set<Map<String, String>> edgeDefaults = new HashSet<Map<String, String>> ();
+
+ final NodeList keys = doc.getElementsByTagName("key");
+
+ for (int i = 0; i < keys.getLength(); i++) {
+ final Node key = keys.item(i);
+ final String id = key.getAttributes().getNamedItem("id").getNodeValue();
+ final String attrName = key.getAttributes().getNamedItem("attr.name").getNodeValue();
+ final String attrType = key.getAttributes().getNamedItem("attr.type").getNodeValue();
+ final String elementType = key.getAttributes().getNamedItem("for").getNodeValue();
+ final Map<String, String> propertyDefinitions = new HashMap<String, String> ();
+
+ propertyDefinitions.put("attr.name", attrName);
+ propertyDefinitions.put("attr.type", attrType);
+
+ final NodeList keyChildren = key.getChildNodes();
+
+ for (int j = 0; j < keyChildren.getLength(); j++) {
+ final Node keyChild = keyChildren.item(j);
+
+ if (keyChild.getNodeType() != Node.ELEMENT_NODE) continue;
+
+ if (keyChild.getNodeName().equals("default")) {
+ propertyDefinitions.put("default", keyChild.getFirstChild().getNodeValue());
+
+ if (elementType.equals("node")) nodeDefaults.add(propertyDefinitions);
+ else if (elementType.equals("edge")) edgeDefaults.add(propertyDefinitions);
+ }
+ }
+
+ if (elementType.equals("node")) {
+ nodePropertyDefinitions.put(id, propertyDefinitions);
+ } else if (elementType.equals("edge")) {
+ edgePropertyDefinitions.put(id, propertyDefinitions);
+ } else {
+ LOGGER.warn("Unknown element type {}, skipping", elementType);
+ }
+ }
+
+ final NodeList graphs = doc.getElementsByTagName("graph");
+
+ for (int i = 0; i < graphs.getLength(); i++) {
+ final Node graph = graphs.item(i);
+ final String graphName = graph.getAttributes().getNamedItem("id").getNodeValue();
+ final NodeList nodesAndEdges = graph.getChildNodes();
+
+ api.getGraph(graphName).storeObjectIndex(ChampObjectIndex.create()
+ .ofName("importAssignedId")
+ .onAnyType()
+ .forField("importAssignedId")
+ .build());
+
+ for (int j = 0; j < nodesAndEdges.getLength(); j++) {
+ final Node nodeOrEdge = nodesAndEdges.item(j);
+
+ if (nodeOrEdge.getNodeType() != Node.ELEMENT_NODE) continue;
+
+ if (nodeOrEdge.getNodeName().equals("node")) {
+ writeNode(api.getGraph(graphName), nodeOrEdge, nodePropertyDefinitions, nodeDefaults);
+ } else if (nodeOrEdge.getNodeName().equals("edge")) {
+ writeEdge(api.getGraph(graphName), nodeOrEdge, edgePropertyDefinitions, edgeDefaults);
+ } else {
+ LOGGER.warn("Unknown object {} found in graphML, skipping", nodeOrEdge.getNodeName());
+ }
+ }
+ }
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Failed to setup DocumentBuilder", e);
+ } catch (SAXException e) {
+ throw new RuntimeException("Failed to parse input stream", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to parse input stream", e);
+ }
+ }
+
+ private void writeEdge(ChampGraph graph, Node edge, Map<String, Map<String, String>> edgePropertyDefinitions, Set<Map<String, String>> edgeDefaults) {
+ final NamedNodeMap edgeAttributes = edge.getAttributes();
+ final NodeList data = edge.getChildNodes();
+ final Object sourceKey = edgeAttributes.getNamedItem("source").getNodeValue();
+ final Object targetKey = edgeAttributes.getNamedItem("target").getNodeValue();
+ ChampObject sourceObject=null;
+ ChampObject targetObject=null;
+
+ try {
+ final Optional<ChampObject> source = graph.queryObjects(Collections.singletonMap("importAssignedId", sourceKey), Optional.empty()).findFirst();
+ final Optional<ChampObject> target = graph.queryObjects(Collections.singletonMap("importAssignedId", targetKey), Optional.empty()).findFirst();
+
+ if (!source.isPresent()) {
+ sourceObject = graph.storeObject(ChampObject.create()
+ .ofType("undefined")
+ .withoutKey()
+ .build(),
+ Optional.empty());
+ } else sourceObject = source.get();
+
+ if (!target.isPresent()) {
+ targetObject = graph.storeObject(ChampObject.create()
+ .ofType("undefined")
+ .withoutKey()
+ .build(),
+ Optional.empty());
+ } else targetObject = target.get();
+
+ } catch (ChampMarshallingException e) {
+ LOGGER.error("Failed to marshall object to backend type, skipping this edge", e);
+ return;
+ } catch (ChampSchemaViolationException e) {
+ LOGGER.error("Source/target object violates schema constraint(s)", e);
+ return;
+ } catch (ChampObjectNotExistsException e) {
+ LOGGER.error("Failed to update existing source/target ChampObject", e);
+ return;
+ } catch (ChampTransactionException e) {
+ LOGGER.error("Failed to commit or rollback transaction", e);
+ }
+
+ final ChampRelationship.Builder champRelBuilder = new ChampRelationship.Builder(sourceObject, targetObject, "undefined");
+
+ for (Map<String, String> defaultProperty : edgeDefaults) {
+ champRelBuilder.property(defaultProperty.get("attr.name"), defaultProperty.get("default"));
+ }
+
+ for (int k = 0; k < data.getLength(); k++) {
+ final Node datum = data.item(k);
+
+ if (datum.getNodeType() != Node.ELEMENT_NODE) continue;
+
+ final String nodeProperty = datum.getAttributes().getNamedItem("key").getNodeValue();
+ final Map<String, String> nodePropertyDefinition = edgePropertyDefinitions.get(nodeProperty);
+
+ switch (nodePropertyDefinition.get("attr.type")) {
+ case "boolean":
+ champRelBuilder.property(nodePropertyDefinition.get("attr.name"), Boolean.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "int":
+ champRelBuilder.property(nodePropertyDefinition.get("attr.name"), Integer.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "long":
+ champRelBuilder.property(nodePropertyDefinition.get("attr.name"), Long.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "float":
+ champRelBuilder.property(nodePropertyDefinition.get("attr.name"), Float.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "double":
+ champRelBuilder.property(nodePropertyDefinition.get("attr.name"), Double.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "string":
+ champRelBuilder.property(nodePropertyDefinition.get("attr.name"), datum.getFirstChild().getNodeValue());
+ break;
+ default:
+ throw new RuntimeException("Unknown node property attr.type " + nodePropertyDefinition.get("attr.type"));
+ }
+ }
+
+ final ChampRelationship relToStore = champRelBuilder.build();
+
+ try {
+ graph.storeRelationship(relToStore, Optional.empty());
+ } catch (ChampMarshallingException e) {
+ LOGGER.warn("Failed to marshall ChampObject to backend type", e);
+ } catch (ChampSchemaViolationException e) {
+ LOGGER.error("Failed to store object (schema violated): " + relToStore, e);
+ } catch (ChampRelationshipNotExistsException e) {
+ LOGGER.error("Failed to update existing ChampRelationship", e);
+ } catch (ChampObjectNotExistsException e) {
+ LOGGER.error("Objects bound to relationship do not exist (should never happen)");
+ } catch (ChampUnmarshallingException e) {
+ LOGGER.error("Failed to unmarshall ChampObject to backend type");
+ } catch (ChampTransactionException e) {
+ LOGGER.error("Failed to commit or rollback transaction");
+ }
+
+ }
+
+ private void writeNode(ChampGraph graph, Node node, Map<String, Map<String, String>> nodePropertyDefinitions, Set<Map<String, String>> nodeDefaults) {
+ final NamedNodeMap nodeAttributes = node.getAttributes();
+ final Object importAssignedId = nodeAttributes.getNamedItem("id").getNodeValue();
+ final NodeList data = node.getChildNodes();
+ final Map<String, Object> properties = new HashMap<String, Object> ();
+
+ for (int k = 0; k < data.getLength(); k++) {
+ final Node datum = data.item(k);
+
+ if (datum.getNodeType() != Node.ELEMENT_NODE) continue;
+
+ final String nodeProperty = datum.getAttributes().getNamedItem("key").getNodeValue();
+ final Map<String, String> nodePropertyDefinition = nodePropertyDefinitions.get(nodeProperty);
+
+ switch (nodePropertyDefinition.get("attr.type")) {
+ case "boolean":
+ properties.put(nodePropertyDefinition.get("attr.name"), Boolean.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "int":
+ properties.put(nodePropertyDefinition.get("attr.name"), Integer.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "long":
+ properties.put(nodePropertyDefinition.get("attr.name"), Long.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "float":
+ properties.put(nodePropertyDefinition.get("attr.name"), Float.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "double":
+ properties.put(nodePropertyDefinition.get("attr.name"), Double.valueOf(datum.getFirstChild().getNodeValue()));
+ break;
+ case "string":
+ properties.put(nodePropertyDefinition.get("attr.name"), datum.getFirstChild().getNodeValue());
+ break;
+ default:
+ throw new RuntimeException("Unknown node property attr.type " + nodePropertyDefinition.get("attr.type"));
+ }
+ }
+
+ if (!properties.containsKey("type")) throw new RuntimeException("No type provided for object (was this GraphML exported by Champ?)");
+
+ final ChampObject.Builder champObjBuilder = new ChampObject.Builder((String) properties.get("type"));
+
+ for (Map<String, String> defaultProperty : nodeDefaults) {
+ champObjBuilder.property(defaultProperty.get("attr.name"), defaultProperty.get("default"));
+ }
+
+ properties.remove("type");
+
+ champObjBuilder.properties(properties)
+ .property("importAssignedId", importAssignedId);
+
+ final ChampObject objectToStore = champObjBuilder.build();
+
+ try {
+ graph.storeObject(objectToStore, Optional.empty());
+ } catch (ChampMarshallingException e) {
+ LOGGER.warn("Failed to marshall ChampObject to backend type", e);
+ } catch (ChampSchemaViolationException e) {
+ LOGGER.error("Failed to store object (schema violated): " + objectToStore, e);
+ } catch (ChampObjectNotExistsException e) {
+ LOGGER.error("Failed to update existing ChampObject", e);
+ } catch (ChampTransactionException e) {
+ LOGGER.error("Failed to commit or rollback transaction");
+ }
+ }
+
+ @Override
+ public void exportData(ChampGraph graph, OutputStream os) {
+
+ final XMLOutputFactory output = XMLOutputFactory.newInstance();
+
+ try {
+ final XMLStreamWriter writer = output.createXMLStreamWriter(os);
+
+ writer.writeStartDocument();
+ writer.writeStartElement("graphml");
+ writer.writeDefaultNamespace("http://graphml.graphdrawing.org/xmlns");
+ writer.writeNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
+ writer.writeAttribute("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", "http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd");
+
+ final List<ChampObject> nodes = new LinkedList<ChampObject> ();
+ final List<ChampRelationship> edges = new LinkedList<ChampRelationship> ();
+ final Map<String, GraphMLKey> nodeKeys = new HashMap<String, GraphMLKey> ();
+ final Map<String, GraphMLKey> edgeKeys = new HashMap<String, GraphMLKey> ();
+ final AtomicInteger elementCount = new AtomicInteger();
+
+ graph.queryObjects(Collections.emptyMap(), Optional.empty()).forEach(object -> {
+ nodes.add(object);
+
+ for (Map.Entry<String, Object> property : object.getProperties().entrySet()) {
+ if (nodeKeys.containsKey(property.getKey())) continue;
+
+ nodeKeys.put(property.getKey(), new GraphMLKey("d" + elementCount.incrementAndGet(), property.getKey(), property.getValue().getClass()));
+ }
+
+ nodeKeys.put("type", new GraphMLKey("d" + elementCount.incrementAndGet(), "type", String.class));
+ });
+
+ graph.queryRelationships(Collections.emptyMap(), Optional.empty()).forEach(relationship -> {
+ edges.add(relationship);
+
+ for (Map.Entry<String, Object> property : relationship.getProperties().entrySet()) {
+ if (nodeKeys.containsKey(property.getKey())) continue;
+
+ edgeKeys.put(property.getKey(), new GraphMLKey("d" + elementCount.incrementAndGet(), property.getKey(), property.getValue().getClass()));
+ }
+
+ edgeKeys.put("type", new GraphMLKey("d" + elementCount.incrementAndGet(), "type", String.class));
+ });
+
+ for (Entry<String, GraphMLKey> nodeKey : nodeKeys.entrySet()) {
+ final GraphMLKey graphMlKey = nodeKey.getValue();
+
+ writer.writeStartElement("key");
+ writer.writeAttribute("id", graphMlKey.id);
+ writer.writeAttribute("for", "node");
+ writer.writeAttribute("attr.name", graphMlKey.attrName);
+ writer.writeAttribute("attr.type", graphMlKey.attrType);
+ writer.writeEndElement();
+ }
+
+ for (Entry<String, GraphMLKey> edgeKey : edgeKeys.entrySet()) {
+ final GraphMLKey graphMlKey = edgeKey.getValue();
+
+ writer.writeStartElement("key");
+ writer.writeAttribute("id", graphMlKey.id);
+ writer.writeAttribute("for", "edge");
+ writer.writeAttribute("attr.name", graphMlKey.attrName);
+ writer.writeAttribute("attr.type", graphMlKey.attrType);
+ writer.writeEndElement();
+ }
+
+ for (ChampObject object : nodes) {
+ try {
+ writer.writeStartElement("node");
+ writer.writeAttribute("id", String.valueOf(object.getKey().get()));
+
+ writer.writeStartElement("data");
+ writer.writeAttribute("key", nodeKeys.get("type").id);
+ writer.writeCharacters(object.getType());
+ writer.writeEndElement();
+
+ for (Entry<String, Object> property : object.getProperties().entrySet()) {
+ final GraphMLKey key = nodeKeys.get(property.getKey());
+
+ writer.writeStartElement("data");
+ writer.writeAttribute("key", key.id);
+ writer.writeCharacters(String.valueOf(property.getValue()));
+ writer.writeEndElement();
+ }
+
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new RuntimeException("Failed to write edge to output stream", e);
+ }
+ }
+
+ for (ChampRelationship relationship : edges) {
+ try {
+ writer.writeStartElement("edge");
+ writer.writeAttribute("id", String.valueOf(relationship.getKey().get()));
+
+ writer.writeStartElement("data");
+ writer.writeAttribute("key", edgeKeys.get("type").id);
+ writer.writeCharacters(relationship.getType());
+ writer.writeEndElement();
+
+ for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
+ final GraphMLKey key = edgeKeys.get(property.getKey());
+
+ writer.writeStartElement("data");
+ writer.writeAttribute("key", key.id);
+ writer.writeCharacters(String.valueOf(property.getValue()));
+ writer.writeEndElement();
+ }
+
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new RuntimeException("Failed to write edge to output stream", e);
+ }
+ }
+
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ writer.flush();
+ } catch (XMLStreamException | ChampTransactionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Importer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Importer.java
new file mode 100644
index 0000000..4fc22ba
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Importer.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.ie;
+
+import java.io.InputStream;
+
+import org.onap.aai.champcore.ChampAPI;
+
+public interface Importer {
+
+ public void importData(ChampAPI api, InputStream is);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampCardinality.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampCardinality.java
new file mode 100644
index 0000000..b1e72f7
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampCardinality.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+public enum ChampCardinality {
+ SINGLE,
+ LIST,
+ SET
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionConstraint.java
new file mode 100644
index 0000000..af44857
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionConstraint.java
@@ -0,0 +1,96 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+@JsonDeserialize(builder = ChampConnectionConstraint.Builder.class)
+public final class ChampConnectionConstraint {
+
+ private final String sourceType;
+ private final String targetType;
+ private final ChampConnectionMultiplicity cardinality;
+
+ private ChampConnectionConstraint() {
+ throw new RuntimeException("Cannot call ConnectionConstraint() constructor");
+ }
+
+ private ChampConnectionConstraint(Builder builder) {
+ this.sourceType = builder.sourceType;
+ this.targetType = builder.targetType;
+ this.cardinality = builder.multiplicity;
+ }
+
+ public String getSourceType() { return sourceType; }
+ public String getTargetType() { return targetType; }
+ public ChampConnectionMultiplicity getMultiplicity() { return cardinality; }
+
+ @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
+ public static class Builder {
+ private final String sourceType;
+ private final String targetType;
+
+ private ChampConnectionMultiplicity multiplicity = ChampConnectionMultiplicity.MANY;
+
+ public Builder(@JsonProperty("sourceType") String sourceType, @JsonProperty("targetType") String targetType) {
+ this.sourceType = sourceType;
+ this.targetType = targetType;
+ }
+
+ public Builder multiplicity(ChampConnectionMultiplicity multiplicity) {
+ this.multiplicity = multiplicity;
+ return this;
+ }
+
+ public ChampConnectionConstraint build() {
+ return new ChampConnectionConstraint(this);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * (getSourceType().hashCode() + getTargetType().hashCode());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ChampConnectionConstraint) {
+ final ChampConnectionConstraint connConstraint = (ChampConnectionConstraint) o;
+
+ if (connConstraint.getSourceType().equals(getSourceType()) &&
+ connConstraint.getTargetType().equals(getTargetType()) &&
+ connConstraint.getMultiplicity().equals(getMultiplicity())) return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "{sourceType: " + getSourceType() +
+ ", targetType: " + getTargetType() +
+ ", multiplicity: " + getMultiplicity()
+ + "}";
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionMultiplicity.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionMultiplicity.java
new file mode 100644
index 0000000..d2742fe
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionMultiplicity.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+public enum ChampConnectionMultiplicity {
+ NONE, //Cannot have any relationships of a type between two object types
+ ONE, //Can have zero or one relationship of a type between two object types
+ MANY //Can have zero or more relationships of a type between two object types
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampElement.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampElement.java
new file mode 100644
index 0000000..4e938f5
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampElement.java
@@ -0,0 +1,35 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import java.util.Map;
+
+public interface ChampElement {
+
+ public boolean isObject();
+ public ChampObject asObject();
+
+ public boolean isRelationship();
+ public ChampRelationship asRelationship();
+
+ public Map<String, Object> getProperties();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampField.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampField.java
new file mode 100644
index 0000000..92c3ea0
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampField.java
@@ -0,0 +1,129 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+@JsonDeserialize(builder = ChampField.Builder.class)
+public final class ChampField implements Comparable<ChampField> {
+
+ private final String name;
+ private final ChampField.Type type;
+
+ private ChampField() {
+ throw new RuntimeException("Cannot use ChampField() constructor");
+ }
+
+ public String getName() { return name; }
+ public ChampField.Type getType() { return type; }
+
+ @JsonIgnore
+ public Class<?> getJavaType() {
+ switch (type) {
+ case BOOLEAN:
+ return Boolean.class;
+ case DOUBLE:
+ return Double.class;
+ case FLOAT:
+ return Float.class;
+ case INTEGER:
+ return Integer.class;
+ case LONG:
+ return Long.class;
+ case STRING:
+ return String.class;
+ default:
+ throw new RuntimeException("Unknown ChampField.Type " + type);
+ }
+ }
+
+ private ChampField(Builder builder) {
+ this.name = builder.name;
+ this.type = builder.type;
+ }
+
+ public static enum Type {
+ STRING,
+ INTEGER,
+ LONG,
+ DOUBLE,
+ FLOAT,
+ BOOLEAN
+ }
+
+ @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
+ public static class Builder {
+ private final String name;
+
+ private ChampField.Type type = ChampField.Type.STRING;
+
+ public Builder(@JsonProperty("name") String name) {
+ this.name = name;
+ }
+
+ public Builder type(ChampField.Type type) {
+ this.type = type;
+ return this;
+ }
+
+ public ChampField build() {
+ return new ChampField(this);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * (getName().hashCode());
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof ChampField) {
+ final ChampField champField = (ChampField) object;
+
+ if (champField.getName().equals(getName())) return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "{name: " + getName() +
+ ", type: " + getType() +
+ "}";
+ }
+
+ @Override
+ public int compareTo(ChampField o) {
+ final int nameComparison = getName().compareTo(o.getName());
+
+ if (nameComparison == 0) {
+ return getType().compareTo(o.getType());
+ }
+
+ return nameComparison;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObject.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObject.java
new file mode 100644
index 0000000..b4e7311
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObject.java
@@ -0,0 +1,280 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import org.onap.aai.champcore.model.fluent.object.CreateChampObjectable;
+import org.onap.aai.champcore.model.fluent.object.impl.CreateChampObjectableImpl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+
+public final class ChampObject implements ChampElement {
+
+ private String type;
+ private Optional<Object> key;
+ private Map<String, Object> properties;
+
+ public static CreateChampObjectable create() {
+ return new CreateChampObjectableImpl();
+ }
+
+ public ChampObject() {
+ }
+
+ private ChampObject(Builder builder) {
+ this.type = builder.type;
+ this.key = builder.key;
+ this.properties = builder.properties;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> Optional<T> getProperty(String key) {
+ if (!properties.containsKey(key)) {
+ return Optional.empty();
+ }
+
+ return Optional.of((T) properties.get(key));
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @JsonIgnore
+ public Optional<Object> getKey() {
+ return key;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ @JsonProperty("key")
+ public Object getKeyValue() {
+ return key.orElse("");
+
+ }
+
+ public ChampObject dropProperties(HashSet<String> safeProperties) {
+ HashSet<String> propertyKeys = new HashSet<>(properties.keySet());
+ for (String key : propertyKeys) {
+ if (!safeProperties.contains(key)) {
+ properties.remove(key);
+ }
+ }
+
+ return this;
+ }
+
+ public static class Builder {
+ private final String type;
+ private final Map<String, Object> properties = new HashMap<String, Object>();
+
+ private Optional<Object> key = Optional.empty();
+
+ public Builder(String type) {
+ if (type == null) {
+ throw new IllegalArgumentException("Type cannot be null");
+ }
+
+ this.type = type;
+ }
+
+ public Builder(ChampObject object) {
+ type = object.getType();
+ key = object.getKey();
+ properties(object.getProperties());
+ }
+
+ public Builder key(Object key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key cannot be set to null");
+ }
+
+ this.key = Optional.of(key);
+ return this;
+ }
+
+ public Builder property(String key, Object value) {
+ if (key == null) {
+ throw new IllegalArgumentException("Property key cannot be null");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("Property value cannot be null");
+ }
+
+ if (ReservedPropertyKeys.contains(key)) {
+ throw new IllegalArgumentException("Property key " + key + " is reserved");
+ }
+
+ properties.put(key, value);
+ return this;
+ }
+
+ public Builder properties(Map<String, Object> properties) {
+ for (Entry<String, Object> property : properties.entrySet()) {
+ property(property.getKey(), property.getValue());
+ }
+
+ return this;
+ }
+
+ public ChampObject build() {
+ return new ChampObject(this);
+ }
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+
+ if (object instanceof ChampObject) {
+ final ChampObject champObj = (ChampObject) object;
+
+ if (getKey().isPresent() && champObj.getKey().isPresent()) {
+
+ if (getKey().get().equals(champObj.getKey().get())) {
+ return true;
+ }
+
+ } else if (!getKey().isPresent() && !champObj.getKey().isPresent()) {
+ if (getType().equals(champObj.getType()) &&
+ getProperties().equals(champObj.getProperties())) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (getKey().isPresent()) {
+ return getKey().get().hashCode();
+ }
+
+ final int returnValue = 31 * (getType().hashCode() + getProperties().hashCode());
+ return returnValue;
+ }
+
+ @Override
+ public String toString() {
+ return "{key: " + (getKey().isPresent() ? getKey().get() : "")
+ + ", type: " + getType()
+ + ", properties: " + getProperties() + "}";
+ }
+
+ public enum ReservedPropertyKeys {
+ CHAMP_OBJECT_TYPE("aai_node_type"),
+ CHAMP_OBJECT_KEY("key");
+
+ private final String text;
+
+ private ReservedPropertyKeys(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+
+ public static boolean contains(String key) {
+ for (ReservedPropertyKeys choice : ReservedPropertyKeys.values()) {
+ if (choice.toString().equals(key)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ public enum IgnoreOnReadPropertyKeys {
+ CHAMP_IMPORT_ASSIGNED_ID("importAssignedId");
+
+ private final String text;
+
+ private IgnoreOnReadPropertyKeys(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+
+ public static boolean contains(String key) {
+ for (IgnoreOnReadPropertyKeys choice : IgnoreOnReadPropertyKeys.values()) {
+ if (choice.toString().equals(key)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ public enum ReservedTypes {
+ ANY("ANY");
+
+ private final String text;
+
+ private ReservedTypes(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+ }
+
+ @Override
+ public boolean isObject() {
+ return true;
+ }
+
+ @Override
+ public ChampObject asObject() {
+ return this;
+ }
+
+ @Override
+ public boolean isRelationship() {
+ return false;
+ }
+
+ @Override
+ public ChampRelationship asRelationship() {
+ throw new UnsupportedOperationException("Cannot call asRelationship() on ChampObject");
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectConstraint.java
new file mode 100644
index 0000000..1a91c7a
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectConstraint.java
@@ -0,0 +1,107 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+@JsonDeserialize(builder = ChampObjectConstraint.Builder.class)
+public final class ChampObjectConstraint {
+
+ private final String type;
+ private final Map<String, ChampPropertyConstraint> propertyConstraints;
+
+ private ChampObjectConstraint() {
+ throw new RuntimeException("Cannot call ChampObjectConstraint() constructor");
+ }
+
+ private ChampObjectConstraint(Builder builder) {
+ this.type = builder.type;
+ this.propertyConstraints = builder.propertyConstraints;
+ }
+
+ public String getType() { return type; }
+ public Set<ChampPropertyConstraint> getPropertyConstraints() { return new HashSet<ChampPropertyConstraint> (propertyConstraints.values()); }
+
+ public Optional<ChampPropertyConstraint> getPropertyConstraint(String fieldName) {
+ if (!propertyConstraints.containsKey(fieldName)) return Optional.empty();
+
+ return Optional.of(propertyConstraints.get(fieldName));
+ }
+
+ @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
+ public static class Builder {
+ private final String type;
+ private final Map<String, ChampPropertyConstraint> propertyConstraints;
+
+ public Builder(@JsonProperty("type") String type) {
+ this.type = type;
+ this.propertyConstraints = new HashMap<String, ChampPropertyConstraint> ();
+ }
+
+ @JsonProperty("propertyConstraints")
+ public Builder constraints(Set<ChampPropertyConstraint> propertyConstraints) {
+
+ for (ChampPropertyConstraint propConstraint : propertyConstraints) {
+ constraint(propConstraint);
+ }
+
+ return this;
+ }
+
+ @JsonIgnore
+ public Builder constraint(ChampPropertyConstraint propConstraint) {
+ propertyConstraints.put(propConstraint.getField().getName(), propConstraint);
+ return this;
+ }
+
+ public ChampObjectConstraint build() {
+ return new ChampObjectConstraint(this);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ChampObjectConstraint) {
+ final ChampObjectConstraint objectConstraint = (ChampObjectConstraint) o;
+
+ if (objectConstraint.getType().equals(getType())) return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "{type: " + getType() +
+ ", propertyConstraints: " + getPropertyConstraints() +
+ "}";
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectIndex.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectIndex.java
new file mode 100644
index 0000000..c16844c
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectIndex.java
@@ -0,0 +1,87 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import org.onap.aai.champcore.model.fluent.index.CreateObjectIndexable;
+import org.onap.aai.champcore.model.fluent.index.impl.CreateObjectIndexableImpl;
+
+public final class ChampObjectIndex {
+
+ private final String name;
+ private final String type;
+ private final ChampField field;
+
+ public static CreateObjectIndexable create() {
+ return new CreateObjectIndexableImpl();
+ }
+
+ private ChampObjectIndex() {
+ throw new RuntimeException("Cannot call ChampObjectIndex() constructor");
+ }
+
+ private ChampObjectIndex(Builder builder) {
+ this.name = builder.name;
+ this.type = builder.type;
+ this.field = builder.field;
+ }
+
+ public String getName() { return name; }
+ public String getType() { return type; }
+ public ChampField getField() { return field; }
+
+ public static class Builder {
+ private final String name;
+ private final String type;
+ private final ChampField field;
+
+ public Builder(String name, String type, ChampField field) {
+ this.name = name;
+ this.type = type;
+ this.field = field;
+ }
+
+ public ChampObjectIndex build() {
+ return new ChampObjectIndex(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "{name: " + getName()
+ + ", type: " + getType()
+ + ", field: " + getField() + "}";
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) return true;
+
+ if (object instanceof ChampObjectIndex) {
+ final ChampObjectIndex objectIndex = (ChampObjectIndex) object;
+
+ if (getName().equals(objectIndex.getName()) &&
+ getField().getName().equals(objectIndex.getField().getName())) return true;
+ }
+
+ return false;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPartition.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPartition.java
new file mode 100644
index 0000000..0292694
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPartition.java
@@ -0,0 +1,148 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.onap.aai.champcore.model.fluent.partition.CreateChampPartitionable;
+import org.onap.aai.champcore.model.fluent.partition.impl.CreateChampPartionableImpl;
+
+public final class ChampPartition {
+
+ private final Set<ChampObject> champObjects;
+ private final Set<ChampRelationship> champRelationships;
+
+ private ChampPartition() {
+ throw new RuntimeException("Cannot call ChampGraph() constructor");
+ }
+
+ private ChampPartition(Builder builder) {
+ this.champObjects = builder.champObjects;
+ this.champRelationships = builder.champRelationships;
+ }
+
+ public static CreateChampPartitionable create() {
+ return new CreateChampPartionableImpl();
+ }
+
+ public Set<ChampObject> getChampObjects() { return champObjects; }
+ public Set<ChampRelationship> getChampRelationships() { return champRelationships; }
+
+ public Set<ChampRelationship> getIncidentRelationships(ChampObject source) {
+ final Set<ChampRelationship> incidentRelationships = new HashSet<ChampRelationship> ();
+
+ for (ChampRelationship relationship : getChampRelationships()) {
+ if (relationship.getSource().equals(source) ||
+ relationship.getTarget().equals(source)) {
+ incidentRelationships.add(relationship);
+ }
+ }
+
+ return incidentRelationships;
+ }
+
+ public Map<String, Set<ChampRelationship>> getIncidentRelationshipsByType(ChampObject source) {
+ final Map<String, Set<ChampRelationship>> incidentRelationships = new HashMap<String, Set<ChampRelationship>> ();
+
+ for (ChampRelationship relationship : getChampRelationships()) {
+ if (relationship.getSource().equals(source) ||
+ relationship.getTarget().equals(source)) {
+ if (!incidentRelationships.containsKey(relationship.getType())) {
+ incidentRelationships.put(relationship.getType(), new HashSet<ChampRelationship> ());
+ }
+
+ incidentRelationships.get(relationship.getType()).add(relationship);
+ }
+ }
+
+ return incidentRelationships;
+ }
+
+ public static class Builder {
+ private final Set<ChampObject> champObjects;
+ private final Set<ChampRelationship> champRelationships;
+
+ public Builder() {
+ this.champObjects = new HashSet<ChampObject> ();
+ this.champRelationships = new HashSet<ChampRelationship> ();
+ }
+
+ public Builder object(ChampObject object) {
+ champObjects.add(object);
+ return this;
+ }
+
+ public Builder relationship(ChampRelationship relationship) {
+ champRelationships.add(relationship);
+ return this;
+ }
+
+ public Builder objects(Set<ChampObject> objects) {
+ champObjects.addAll(objects);
+ return this;
+ }
+
+ public Builder relationships(Set<ChampRelationship> relationships) {
+ champRelationships.addAll(relationships);
+ return this;
+ }
+
+ public ChampPartition build() {
+ return new ChampPartition(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append("{objects: [");
+
+ for (ChampObject object : champObjects) {
+ sb.append(object.toString());
+ sb.append(",");
+ }
+
+ if (sb.charAt(sb.length() - 1) == ',') {
+ sb.deleteCharAt(sb.length() - 1); //Delete last comma
+ }
+
+ sb.append("], relationships: [");
+
+ for (ChampRelationship relationship : champRelationships) {
+ sb.append(relationship.toString());
+ sb.append(",");
+ }
+
+ if (sb.charAt(sb.length() - 1) == ',') {
+ sb.deleteCharAt(sb.length() - 1); //Delete last comma
+ }
+
+ sb.append("]}");
+
+ return sb.toString();
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPropertyConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPropertyConstraint.java
new file mode 100644
index 0000000..6008d36
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPropertyConstraint.java
@@ -0,0 +1,110 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+@JsonDeserialize(builder = ChampPropertyConstraint.Builder.class)
+public final class ChampPropertyConstraint implements Comparable<ChampPropertyConstraint> {
+
+ private final ChampField field;
+ private final boolean required;
+ private final ChampCardinality cardinality;
+
+ private ChampPropertyConstraint() {
+ throw new RuntimeException("Cannot call ChampPropertyConstraint() constructor");
+ }
+
+ private ChampPropertyConstraint(Builder builder) {
+ this.field = builder.field;
+ this.required = builder.required;
+ this.cardinality = builder.cardinality;
+ }
+
+ public ChampField getField() { return field; }
+ public boolean isRequired() { return required; }
+ public ChampCardinality getCardinality() { return cardinality; }
+
+ @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
+ public static class Builder {
+ private final ChampField field;
+
+ private boolean required = false;
+ private ChampCardinality cardinality = ChampCardinality.SINGLE;
+
+ public Builder(@JsonProperty("field") ChampField field) {
+ this.field = field;
+ }
+
+ public Builder required(boolean required) {
+ this.required = required;
+ return this;
+ }
+
+ public Builder cardinality(ChampCardinality cardinality) {
+ this.cardinality = cardinality;
+ return this;
+ }
+
+ public ChampPropertyConstraint build() {
+ return new ChampPropertyConstraint(this);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * (getField().hashCode());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ChampPropertyConstraint) {
+ final ChampPropertyConstraint propertyConstraint = (ChampPropertyConstraint) o;
+
+ if (propertyConstraint.getField().equals(getField()))
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "{field: " + getField() +
+ ", required: " + isRequired() +
+ ", cardinality: " + getCardinality() +
+ "}";
+ }
+
+ @Override
+ public int compareTo(ChampPropertyConstraint o) {
+ final int fieldComparison = o.getField().compareTo(getField());
+
+ if (fieldComparison == 0) {
+ return o.getCardinality().compareTo(getCardinality());
+ }
+
+ return fieldComparison;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationship.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationship.java
new file mode 100644
index 0000000..2d7f033
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationship.java
@@ -0,0 +1,220 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+
+import org.onap.aai.champcore.model.fluent.relationship.CreateChampRelationshipable;
+import org.onap.aai.champcore.model.fluent.relationship.impl.CreateChampRelationshipableImpl;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public final class ChampRelationship implements ChampElement {
+ private String type; //AKA edge label
+ private Optional<Object> key;
+ private Map<String, Object> properties;
+ private ChampObject source;
+ private ChampObject target;
+
+ public static CreateChampRelationshipable create() {
+ return new CreateChampRelationshipableImpl();
+ }
+
+ public ChampRelationship() { //Not instantiable
+ }
+
+ private ChampRelationship(Builder builder) {
+ this.properties = builder.properties;
+ this.source = builder.source;
+ this.target = builder.target;
+ this.type = builder.type;
+ this.key = builder.key;
+ }
+
+ @JsonIgnore
+ public Optional<Object> getKey() {
+ if (key == null) {
+ return Optional.empty ();
+ } else {
+ return key;
+ }
+ }
+
+ @JsonProperty("key")
+ public String getKeyValue() {
+ return (getKey().isPresent() ? getKey().get() : "").toString();
+ }
+
+ public ChampObject getSource() {
+ return source;
+ }
+
+ public ChampObject getTarget() {
+ return target;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> Optional<T> getProperty(String key) {
+ if (!properties.containsKey(key)) return Optional.empty();
+
+ return Optional.of((T) properties.get(key));
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ public static class Builder {
+ private final Map<String, Object> properties = new HashMap<String, Object> ();
+ private final ChampObject source;
+ private final ChampObject target;
+ private final String type;
+
+ private Optional<Object> key = Optional.empty();
+
+ public Builder(ChampObject source, ChampObject target, String type) {
+ this.source = source;
+ this.target = target;
+ this.type = type;
+ }
+
+ public Builder(ChampRelationship relationship) {
+ this.source = relationship.source;
+ this.target = relationship.target;
+ this.type = relationship.type;
+
+ properties.putAll(relationship.getProperties());
+ }
+
+ public Builder key(Object key) {
+ this.key = Optional.of(key);
+ return this;
+ }
+
+ public Builder properties(Map<String, Object> properties) {
+ for (Entry<String, Object> property : properties.entrySet()) {
+ property(property.getKey(), property.getValue());
+ }
+
+ return this;
+ }
+
+ public Builder property(String key, Object value) {
+ if (ChampRelationship.ReservedPropertyKeys.contains(key)) throw new IllegalArgumentException("Cannot make use of reserved property key " + key);
+
+ properties.put(key, value);
+ return this;
+ }
+
+ public ChampRelationship build() {
+ return new ChampRelationship(this);
+ }
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) return true;
+ if (object instanceof ChampRelationship) {
+ final ChampRelationship champRelationship = (ChampRelationship) object;
+
+ if (getKey().isPresent() && champRelationship.getKey().isPresent()) {
+ if (getKey().get().equals(champRelationship.getKey().get())) return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "{key: " + (getKey().isPresent() ? getKey().get() : "")
+ + ", type: " + getType()
+ + ", source: " + getSource()
+ + ", target: " + getTarget()
+ + ", properties: " + getProperties() + "}";
+ }
+
+ public enum ReservedPropertyKeys {
+ CHAMP_RELATIONSHIP_TYPE ("relationshipType"),
+ CHAMP_RELATIONSHIP_KEY ("key");
+
+ private final String text;
+
+ private ReservedPropertyKeys(final String text) {
+ this.text = text;
+ }
+
+ public String toString() {
+ return text;
+ }
+
+ public static boolean contains(String key) {
+ for (ReservedPropertyKeys choice : ReservedPropertyKeys.values()) {
+ if (choice.toString().equals(key)) return true;
+ }
+
+ return false;
+ }
+ }
+
+ public enum ReservedTypes {
+ ANY ("ANY");
+
+ private final String text;
+
+ private ReservedTypes(final String text) {
+ this.text = text;
+ }
+
+ public String toString() {
+ return text;
+ }
+ }
+
+ @Override
+ public boolean isObject() {
+ return false;
+ }
+
+ @Override
+ public ChampObject asObject() {
+ throw new UnsupportedOperationException("Cannot call asObject() on ChampRelationship");
+ }
+
+ @Override
+ public boolean isRelationship() {
+ return true;
+ }
+
+ @Override
+ public ChampRelationship asRelationship() {
+ return this;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipConstraint.java
new file mode 100644
index 0000000..b571205
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipConstraint.java
@@ -0,0 +1,139 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+@JsonDeserialize(builder = ChampRelationshipConstraint.Builder.class)
+public final class ChampRelationshipConstraint {
+
+ private final String type;
+ private final Map<String, ChampPropertyConstraint> propertyConstraints;
+ private final Set<ChampConnectionConstraint> connectionConstraints;
+
+ private ChampRelationshipConstraint() {
+ throw new RuntimeException("Cannot call ChampObjectConstraint() constructor");
+ }
+
+ private ChampRelationshipConstraint(Builder builder) {
+ this.type = builder.type;
+ this.propertyConstraints = builder.propertyConstraints;
+ this.connectionConstraints = builder.connectionConstraints;
+ }
+
+ public String getType() { return type; }
+ public Set<ChampPropertyConstraint> getPropertyConstraints() { return new HashSet<ChampPropertyConstraint> (propertyConstraints.values()); }
+
+ public Optional<ChampPropertyConstraint> getPropertyConstraint(String fieldName) {
+ if (!propertyConstraints.containsKey(fieldName)) return Optional.empty();
+
+ return Optional.of(propertyConstraints.get(fieldName));
+ }
+
+ public Set<ChampConnectionConstraint> getConnectionConstraints() { return connectionConstraints; }
+
+ public Optional<ChampConnectionConstraint> getConnectionConstraint(ChampRelationship incidentRelationship) {
+ if (!incidentRelationship.getType().equals(getType())) return Optional.empty();
+
+ final String sourceType = incidentRelationship.getSource().getType();
+ final String targetType = incidentRelationship.getTarget().getType();
+
+ for (ChampConnectionConstraint connConstraint : getConnectionConstraints()) {
+ if (connConstraint.getSourceType().equals(sourceType) &&
+ connConstraint.getTargetType().equals(targetType)) return Optional.of(connConstraint);
+ }
+
+ return Optional.empty();
+ }
+
+ @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
+ public static class Builder {
+ private final String type;
+ private final Map<String, ChampPropertyConstraint> propertyConstraints;
+ private final Set<ChampConnectionConstraint> connectionConstraints;
+
+ public Builder(@JsonProperty("type") String type) {
+ this.type = type;
+ this.propertyConstraints = new HashMap<String, ChampPropertyConstraint> ();
+ this.connectionConstraints = new HashSet<ChampConnectionConstraint> ();
+ }
+
+ public Builder propertyConstraints(Set<ChampPropertyConstraint> propertyConstraints) {
+
+ for (ChampPropertyConstraint propConstraint : propertyConstraints) {
+ constraint(propConstraint);
+ }
+
+ return this;
+ }
+
+ public Builder connectionConstraints(Set<ChampConnectionConstraint> connectionConstraints) {
+ this.connectionConstraints.addAll(connectionConstraints);
+ return this;
+ }
+
+ @JsonIgnore
+ public Builder constraint(ChampPropertyConstraint propConstraint) {
+ propertyConstraints.put(propConstraint.getField().getName(), propConstraint);
+ return this;
+ }
+
+ @JsonIgnore
+ public Builder constraint(ChampConnectionConstraint connConstraint) {
+ connectionConstraints.add(connConstraint);
+ return this;
+ }
+ public ChampRelationshipConstraint build() {
+ return new ChampRelationshipConstraint(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "{type: " + getType() +
+ ", connectionConstraints: " + getConnectionConstraints() +
+ ", propertyConstraints: " + getPropertyConstraints() +
+ "}";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ChampRelationshipConstraint) {
+ final ChampRelationshipConstraint relConstraint = (ChampRelationshipConstraint) o;
+
+ if (relConstraint.getType().equals(getType()) &&
+ relConstraint.getConnectionConstraints().equals(getConnectionConstraints()) &&
+ relConstraint.getPropertyConstraints().equals(getPropertyConstraints())) return true;
+ }
+
+ return false;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipIndex.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipIndex.java
new file mode 100644
index 0000000..03310ba
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipIndex.java
@@ -0,0 +1,87 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import org.onap.aai.champcore.model.fluent.index.CreateRelationshipIndexable;
+import org.onap.aai.champcore.model.fluent.index.impl.CreateRelationshipIndexableImpl;
+
+public final class ChampRelationshipIndex {
+
+ private final String name;
+ private final String type;
+ private final ChampField field;
+
+ public static CreateRelationshipIndexable create() {
+ return new CreateRelationshipIndexableImpl();
+ }
+
+ private ChampRelationshipIndex() {
+ throw new RuntimeException("Cannot call ChampRelationshipIndex() constructor");
+ }
+
+ private ChampRelationshipIndex(Builder builder) {
+ this.name = builder.name;
+ this.type = builder.type;
+ this.field = builder.field;
+ }
+
+ public String getName() { return name; }
+ public String getType() { return type; }
+ public ChampField getField() { return field; }
+
+ public static class Builder {
+ private final String name;
+ private final String type;
+ private final ChampField field;
+
+ public Builder(String name, String type, ChampField field) {
+ this.name = name;
+ this.type = type;
+ this.field = field;
+ }
+
+ public ChampRelationshipIndex build() {
+ return new ChampRelationshipIndex(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "{name: " + getName()
+ + ", type: " + getType()
+ + ", field: " + getField() + "}";
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) return true;
+
+ if (object instanceof ChampRelationshipIndex) {
+ final ChampRelationshipIndex relationshipIndex = (ChampRelationshipIndex) object;
+
+ if (getName().equals(relationshipIndex.getName()) &&
+ getField().getName().equals(relationshipIndex.getField().getName())) return true;
+ }
+
+ return false;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampSchema.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampSchema.java
new file mode 100644
index 0000000..81b97bd
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampSchema.java
@@ -0,0 +1,148 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+
+import org.onap.aai.champcore.model.fluent.schema.CreateChampSchemable;
+import org.onap.aai.champcore.model.fluent.schema.impl.CreateChampSchemableImpl;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+@JsonDeserialize(builder = ChampSchema.Builder.class)
+public final class ChampSchema {
+
+ private final Map<String, ChampObjectConstraint> objectConstraints;
+ private final Map<String, ChampRelationshipConstraint> relationshipConstraints;
+
+ private ChampSchema() {
+ throw new RuntimeException("Cannot call ChampSchema() constructor");
+ }
+
+ private ChampSchema(Builder builder) {
+ this.objectConstraints = builder.objectConstraints;
+ this.relationshipConstraints = builder.relationshipConstraints;
+ }
+
+ public static CreateChampSchemable create() {
+ return new CreateChampSchemableImpl();
+ }
+
+ public Optional<ChampObjectConstraint> getObjectConstraint(String type) {
+ if (!getObjectConstraints().containsKey(type)) return Optional.empty();
+
+ return Optional.of(getObjectConstraints().get(type));
+ }
+
+ public Optional<ChampRelationshipConstraint> getRelationshipConstraint(String type) {
+ if (!getRelationshipConstraints().containsKey(type)) return Optional.empty();
+
+ return Optional.of(getRelationshipConstraints().get(type));
+ }
+
+ public Map<String, ChampObjectConstraint> getObjectConstraints() {
+ return objectConstraints;
+ }
+
+ public Map<String, ChampRelationshipConstraint> getRelationshipConstraints() {
+ return relationshipConstraints;
+ }
+
+ @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
+ public static class Builder {
+ private Map<String, ChampObjectConstraint> objectConstraints = new HashMap<String, ChampObjectConstraint> ();
+ private Map<String, ChampRelationshipConstraint> relationshipConstraints = new HashMap<String, ChampRelationshipConstraint> ();
+
+ public Builder() {}
+
+ public Builder(ChampSchema schema) {
+ objectConstraints.putAll(schema.getObjectConstraints());
+ relationshipConstraints.putAll(schema.getRelationshipConstraints());
+ }
+
+ public Builder objectConstraints(Map<String, ChampObjectConstraint> objectConstraints) {
+ this.objectConstraints.putAll(objectConstraints);
+ return this;
+ }
+
+ public Builder relationshipConstraints(Map<String, ChampRelationshipConstraint> relationshipConstraints) {
+ this.relationshipConstraints.putAll(relationshipConstraints);
+ return this;
+ }
+
+ @JsonIgnore
+ public Builder constraint(ChampObjectConstraint objConstraint) {
+ objectConstraints.put(objConstraint.getType(), objConstraint);
+ return this;
+ }
+
+ @JsonIgnore
+ public Builder constraint(ChampRelationshipConstraint relConstraint) {
+ relationshipConstraints.put(relConstraint.getType(), relConstraint);
+ return this;
+ }
+
+ public ChampSchema build() {
+ return new ChampSchema(this);
+ }
+ }
+
+ @Override
+ public boolean equals(Object schema) {
+ if (schema instanceof ChampSchema) {
+
+ for (Entry<String, ChampObjectConstraint> objConstraint : getObjectConstraints().entrySet()) {
+ final Optional<ChampObjectConstraint> champObjConstraint = ((ChampSchema) schema).getObjectConstraint(objConstraint.getKey());
+
+ if (!champObjConstraint.isPresent() ||
+ !champObjConstraint.get().equals(objConstraint.getValue())) return false;
+ }
+
+ for (Entry<String, ChampRelationshipConstraint> relConstraint : getRelationshipConstraints().entrySet()) {
+ final Optional<ChampRelationshipConstraint> champRelConstraint = ((ChampSchema) schema).getRelationshipConstraint(relConstraint.getKey());
+
+ if (!champRelConstraint.isPresent() ||
+ !champRelConstraint.get().equals(relConstraint.getValue())) return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "{objectConstraints: " + getObjectConstraints() +
+ ", relationshipConstraints: " + getRelationshipConstraints() +
+ "}";
+ }
+
+ public static ChampSchema emptySchema() {
+ return new ChampSchema.Builder().build();
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/BuildStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/BuildStep.java
new file mode 100644
index 0000000..6619b90
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/BuildStep.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent;
+
+public interface BuildStep<T> {
+ public T build();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/KeyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/KeyStep.java
new file mode 100644
index 0000000..0be4ac3
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/KeyStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent;
+
+public interface KeyStep<T> {
+ public T withKey(Object key);
+ public T withoutKey();
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/PropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/PropertiesStep.java
new file mode 100644
index 0000000..bac8878
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/PropertiesStep.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent;
+
+import java.util.Map;
+
+public interface PropertiesStep<T> {
+
+ public T withProperty(String key, Object value);
+ public T withProperties(Map<String, Object> properties);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateObjectIndexable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateObjectIndexable.java
new file mode 100644
index 0000000..ccace48
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateObjectIndexable.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index;
+
+public interface CreateObjectIndexable {
+
+ public ObjectIndexTypeStep ofName(String name);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateRelationshipIndexable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateRelationshipIndexable.java
new file mode 100644
index 0000000..e40a86a
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateRelationshipIndexable.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index;
+
+public interface CreateRelationshipIndexable {
+
+ public RelationshipIndexTypeStep ofName(String name);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexFieldStep.java
new file mode 100644
index 0000000..869cdd6
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexFieldStep.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index;
+
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface ObjectIndexFieldStep {
+
+ public BuildStep<ChampObjectIndex> forField(String fieldName);
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexTypeStep.java
new file mode 100644
index 0000000..fc8db8a
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexTypeStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index;
+
+public interface ObjectIndexTypeStep {
+
+ public ObjectIndexFieldStep onType(String objectType);
+ public ObjectIndexFieldStep onAnyType();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexFieldStep.java
new file mode 100644
index 0000000..babd59e
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexFieldStep.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index;
+
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface RelationshipIndexFieldStep {
+
+ public BuildStep<ChampRelationshipIndex> forField(String fieldName);
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexTypeStep.java
new file mode 100644
index 0000000..094f872
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexTypeStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index;
+
+public interface RelationshipIndexTypeStep {
+
+ public RelationshipIndexFieldStep onType(String objectType);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateObjectIndexableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateObjectIndexableImpl.java
new file mode 100644
index 0000000..1e0eb1b
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateObjectIndexableImpl.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index.impl;
+
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+import org.onap.aai.champcore.model.fluent.index.CreateObjectIndexable;
+import org.onap.aai.champcore.model.fluent.index.ObjectIndexFieldStep;
+import org.onap.aai.champcore.model.fluent.index.ObjectIndexTypeStep;
+
+public final class CreateObjectIndexableImpl implements CreateObjectIndexable {
+
+ @Override
+ public ObjectIndexTypeStep ofName(String name) {
+ return new ObjectIndexTypeStep() {
+
+ @Override
+ public ObjectIndexFieldStep onType(String objectType) {
+ return new ObjectIndexFieldStep() {
+
+ @Override
+ public BuildStep<ChampObjectIndex> forField(String fieldName) {
+ return new BuildStep<ChampObjectIndex> () {
+
+ @Override
+ public ChampObjectIndex build() {
+ return new ChampObjectIndex.Builder(
+ name, objectType, new ChampField.Builder(fieldName).build()
+ ).build();
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public ObjectIndexFieldStep onAnyType() {
+ return new ObjectIndexFieldStep() {
+
+ @Override
+ public BuildStep<ChampObjectIndex> forField(String fieldName) {
+ return new BuildStep<ChampObjectIndex> () {
+
+ @Override
+ public ChampObjectIndex build() {
+ return new ChampObjectIndex.Builder(
+ name, ChampObject.ReservedTypes.ANY.toString(), new ChampField.Builder(fieldName).build()
+ ).build();
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateRelationshipIndexableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateRelationshipIndexableImpl.java
new file mode 100644
index 0000000..40d105e
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateRelationshipIndexableImpl.java
@@ -0,0 +1,58 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.index.impl;
+
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+import org.onap.aai.champcore.model.fluent.index.CreateRelationshipIndexable;
+import org.onap.aai.champcore.model.fluent.index.RelationshipIndexFieldStep;
+import org.onap.aai.champcore.model.fluent.index.RelationshipIndexTypeStep;
+
+public final class CreateRelationshipIndexableImpl implements CreateRelationshipIndexable {
+
+ @Override
+ public RelationshipIndexTypeStep ofName(String name) {
+ return new RelationshipIndexTypeStep() {
+
+ @Override
+ public RelationshipIndexFieldStep onType(String relationshipType) {
+ return new RelationshipIndexFieldStep() {
+
+ @Override
+ public BuildStep<ChampRelationshipIndex> forField(String fieldName) {
+ return new BuildStep<ChampRelationshipIndex> () {
+
+ @Override
+ public ChampRelationshipIndex build() {
+ return new ChampRelationshipIndex.Builder(
+ name, relationshipType, new ChampField.Builder(fieldName).build()
+ ).build();
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/CreateChampObjectable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/CreateChampObjectable.java
new file mode 100644
index 0000000..b062a09
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/CreateChampObjectable.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.object;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.fluent.KeyStep;
+
+public interface CreateChampObjectable {
+ public KeyStep<ObjectBuildOrPropertiesStep> ofType(String type);
+ public KeyStep<ObjectBuildOrPropertiesStep> from(ChampObject object);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStep.java
new file mode 100644
index 0000000..d982b81
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStep.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.object;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+import org.onap.aai.champcore.model.fluent.PropertiesStep;
+
+public interface ObjectBuildOrPropertiesStep extends BuildStep<ChampObject>, PropertiesStep<ObjectBuildOrPropertiesStep> {
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java
new file mode 100644
index 0000000..7938346
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.object;
+
+import java.util.Map;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObject.Builder;
+
+public final class ObjectBuildOrPropertiesStepImpl implements ObjectBuildOrPropertiesStep {
+
+ private final ChampObject.Builder builder;
+
+ public ObjectBuildOrPropertiesStepImpl(Builder builder) {
+ this.builder = builder;
+ }
+
+ @Override
+ public ChampObject build() {
+ return builder.build();
+ }
+
+ @Override
+ public ObjectBuildOrPropertiesStep withProperty(String key, Object value) {
+ builder.property(key, value);
+ return this;
+ }
+
+ @Override
+ public ObjectBuildOrPropertiesStep withProperties(Map<String, Object> properties) {
+ builder.properties(properties);
+ return this;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectKeyStepImpl.java
new file mode 100644
index 0000000..d05c84d
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectKeyStepImpl.java
@@ -0,0 +1,47 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.object;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObject.Builder;
+import org.onap.aai.champcore.model.fluent.KeyStep;
+
+public final class ObjectKeyStepImpl implements KeyStep<ObjectBuildOrPropertiesStep> {
+
+ private final ChampObject.Builder builder;
+
+ public ObjectKeyStepImpl(Builder builder) {
+ this.builder = builder;
+ }
+
+ @Override
+ public ObjectBuildOrPropertiesStep withKey(Object key) {
+ builder.key(key);
+ return new ObjectBuildOrPropertiesStepImpl(builder);
+ }
+
+ @Override
+ public ObjectBuildOrPropertiesStep withoutKey() {
+ return new ObjectBuildOrPropertiesStepImpl(builder);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/impl/CreateChampObjectableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/impl/CreateChampObjectableImpl.java
new file mode 100644
index 0000000..242c4c8
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/impl/CreateChampObjectableImpl.java
@@ -0,0 +1,42 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.object.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.fluent.KeyStep;
+import org.onap.aai.champcore.model.fluent.object.CreateChampObjectable;
+import org.onap.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.object.ObjectKeyStepImpl;
+
+public final class CreateChampObjectableImpl implements CreateChampObjectable {
+
+ @Override
+ public KeyStep<ObjectBuildOrPropertiesStep> ofType(String type) {
+ return new ObjectKeyStepImpl(new ChampObject.Builder(type));
+ }
+
+ @Override
+ public KeyStep<ObjectBuildOrPropertiesStep> from(ChampObject object) {
+ return new ObjectKeyStepImpl(new ChampObject.Builder(object));
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/CreateChampPartitionable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/CreateChampPartitionable.java
new file mode 100644
index 0000000..e65ca4f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/CreateChampPartitionable.java
@@ -0,0 +1,34 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.partition;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface CreateChampPartitionable extends BuildStep<ChampPartition> {
+
+ public CreateChampPartitionable withObject(ChampObject object);
+ public CreateChampPartitionable withRelationship(ChampRelationship relationship);
+ public ChampPartition build();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/impl/CreateChampPartionableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/impl/CreateChampPartionableImpl.java
new file mode 100644
index 0000000..cfd284e
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/impl/CreateChampPartionableImpl.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.partition.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.partition.CreateChampPartitionable;
+
+public final class CreateChampPartionableImpl implements CreateChampPartitionable {
+
+ private final ChampPartition.Builder builder;
+
+ public CreateChampPartionableImpl() {
+ this.builder = new ChampPartition.Builder();
+ }
+
+ @Override
+ public CreateChampPartitionable withObject(ChampObject object) {
+ builder.object(object);
+ return this;
+ }
+
+ @Override
+ public CreateChampPartitionable withRelationship(ChampRelationship relationship) {
+ builder.relationship(relationship);
+ return this;
+ }
+
+ @Override
+ public ChampPartition build() {
+ return builder.build();
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/CreateChampRelationshipable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/CreateChampRelationshipable.java
new file mode 100644
index 0000000..bb89c21
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/CreateChampRelationshipable.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.KeyStep;
+
+public interface CreateChampRelationshipable {
+ public KeyStep<SourceStep> ofType(String type);
+ public KeyStep<RelationshipBuildOrPropertiesStep> from(ChampRelationship relationship);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java
new file mode 100644
index 0000000..44ee875
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+import org.onap.aai.champcore.model.fluent.PropertiesStep;
+
+public interface RelationshipBuildOrPropertiesStep extends BuildStep<ChampRelationship>, PropertiesStep<RelationshipBuildOrPropertiesStep> {
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceBuildOrPropertiesStep.java
new file mode 100644
index 0000000..5e02fa6
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceBuildOrPropertiesStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface SourceBuildOrPropertiesStep {
+
+ public SourceBuildOrPropertiesStep withProperty(String key, Object value);
+ public TargetStep build();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceFromStep.java
new file mode 100644
index 0000000..18f1da6
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceFromStep.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+import org.onap.aai.champcore.model.ChampObject;
+
+public interface SourceFromStep {
+
+ public SourceBuildOrPropertiesStep from(ChampObject object);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceKeyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceKeyStep.java
new file mode 100644
index 0000000..8e475e8
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceKeyStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface SourceKeyStep {
+
+ public SourceBuildOrPropertiesStep withKey(Object key);
+ public SourceBuildOrPropertiesStep withoutKey();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceStep.java
new file mode 100644
index 0000000..843cf4f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceStep.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface SourceStep {
+ public SourceTypeOrFromStep withSource();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeOrFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeOrFromStep.java
new file mode 100644
index 0000000..5ae8550
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeOrFromStep.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface SourceTypeOrFromStep extends SourceTypeStep, SourceFromStep {
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeStep.java
new file mode 100644
index 0000000..bff8902
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface SourceTypeStep {
+
+ public SourceKeyStep ofType(String type);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetBuildOrPropertiesStep.java
new file mode 100644
index 0000000..1a8ec49
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetBuildOrPropertiesStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface TargetBuildOrPropertiesStep {
+
+ public TargetBuildOrPropertiesStep withProperty(String key, Object value);
+ public RelationshipBuildOrPropertiesStep build();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetFromStep.java
new file mode 100644
index 0000000..cd1551c
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetFromStep.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+import org.onap.aai.champcore.model.ChampObject;
+
+public interface TargetFromStep {
+
+ public TargetBuildOrPropertiesStep from(ChampObject object);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetKeyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetKeyStep.java
new file mode 100644
index 0000000..a834edc
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetKeyStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface TargetKeyStep {
+
+ public TargetBuildOrPropertiesStep withKey(Object key);
+ public TargetBuildOrPropertiesStep withoutKey();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetStep.java
new file mode 100644
index 0000000..372d298
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetStep.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface TargetStep {
+ public TargetTypeOrFromStep withTarget();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeOrFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeOrFromStep.java
new file mode 100644
index 0000000..1631d88
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeOrFromStep.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface TargetTypeOrFromStep extends TargetTypeStep, TargetFromStep {
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeStep.java
new file mode 100644
index 0000000..32f4f3d
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship;
+
+public interface TargetTypeStep {
+
+ public TargetKeyStep ofType(String type);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java
new file mode 100644
index 0000000..ebc194e
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.KeyStep;
+import org.onap.aai.champcore.model.fluent.relationship.SourceStep;
+
+public final class ChampRelationshipKeyStepImpl implements KeyStep<SourceStep> {
+
+ private final String type;
+ private final ChampRelationship relationship;
+
+ public ChampRelationshipKeyStepImpl(String type) {
+ this.type = type;
+ this.relationship = null;
+ }
+
+ public ChampRelationshipKeyStepImpl(ChampRelationship relationship) {
+ this.type = null;
+ this.relationship = relationship;
+ }
+
+ @Override
+ public SourceStep withKey(Object key) {
+ return new SourceStepImpl(type, relationship, key);
+ }
+
+ @Override
+ public SourceStep withoutKey() {
+ return new SourceStepImpl(type, relationship, null);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java
new file mode 100644
index 0000000..caf1763
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.KeyStep;
+import org.onap.aai.champcore.model.fluent.relationship.CreateChampRelationshipable;
+import org.onap.aai.champcore.model.fluent.relationship.RelationshipBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.SourceStep;
+
+public final class CreateChampRelationshipableImpl implements CreateChampRelationshipable {
+
+ @Override
+ public KeyStep<SourceStep> ofType(String type) {
+ return new ChampRelationshipKeyStepImpl(type);
+ }
+
+ @Override
+ public KeyStep<RelationshipBuildOrPropertiesStep> from(ChampRelationship relationship) {
+ return new KeyStep<RelationshipBuildOrPropertiesStep> () {
+
+ @Override
+ public RelationshipBuildOrPropertiesStep withKey(Object key) {
+ return new RelationshipBuildOrPropertiesStepImpl(new ChampRelationship.Builder(relationship).key(key));
+ }
+
+ @Override
+ public RelationshipBuildOrPropertiesStep withoutKey() {
+ return new RelationshipBuildOrPropertiesStepImpl(new ChampRelationship.Builder(relationship));
+ }
+ };
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java
new file mode 100644
index 0000000..74d0ffb
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java
@@ -0,0 +1,54 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import java.util.Map;
+
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.RelationshipBuildOrPropertiesStep;
+
+public final class RelationshipBuildOrPropertiesStepImpl implements RelationshipBuildOrPropertiesStep {
+
+ private final ChampRelationship.Builder relationshipBuilder;
+
+ public RelationshipBuildOrPropertiesStepImpl(ChampRelationship.Builder relationshipBuilder) {
+ this.relationshipBuilder = relationshipBuilder;
+ }
+
+ @Override
+ public ChampRelationship build() {
+ return relationshipBuilder.build();
+ }
+
+ @Override
+ public RelationshipBuildOrPropertiesStep withProperty(String key, Object value) {
+ relationshipBuilder.property(key, value);
+ return this;
+ }
+
+ @Override
+ public RelationshipBuildOrPropertiesStep withProperties(Map<String, Object> properties) {
+ relationshipBuilder.properties(properties);
+ return this;
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java
new file mode 100644
index 0000000..70d1deb
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.SourceBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.TargetStep;
+
+public final class SourceBuildOrPropertiesStepImpl implements SourceBuildOrPropertiesStep {
+
+ private ChampObject.Builder sourceBuilder;
+ private Object relationshipKey;
+ private ChampRelationship relationship;
+ private String relationshipType;
+
+ public SourceBuildOrPropertiesStepImpl(String relationshipType, ChampRelationship relationship,
+ Object relationshipKey, ChampObject.Builder sourceBuilder) {
+ this.relationshipType = relationshipType;
+ this.relationship = relationship;
+ this.relationshipKey = relationshipKey;
+ this.sourceBuilder = sourceBuilder;
+ }
+
+ @Override
+ public SourceBuildOrPropertiesStep withProperty(String key, Object value) {
+ sourceBuilder.property(key, value);
+ return this;
+ }
+
+ @Override
+ public TargetStep build() {
+ return new TargetStepImpl(relationshipType, relationship, relationshipKey, sourceBuilder.build());
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceKeyStepImpl.java
new file mode 100644
index 0000000..d1a6184
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceKeyStepImpl.java
@@ -0,0 +1,56 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObject.Builder;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.SourceBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.SourceKeyStep;
+
+public final class SourceKeyStepImpl implements SourceKeyStep {
+
+ private final String relationshipType;
+ private final ChampRelationship relationship;
+ private final Object relationshipKey;
+ private final ChampObject.Builder sourceBuilder;
+
+ public SourceKeyStepImpl(String relationshipType, ChampRelationship relationship, Object relationshipKey,
+ Builder sourceBuilder) {
+ this.relationshipType = relationshipType;
+ this.relationship = relationship;
+ this.relationshipKey = relationshipKey;
+ this.sourceBuilder = sourceBuilder;
+ }
+
+ @Override
+ public SourceBuildOrPropertiesStep withKey(Object key) {
+ sourceBuilder.key(key);
+ return new SourceBuildOrPropertiesStepImpl(relationshipType, relationship, relationshipKey, sourceBuilder);
+ }
+
+ @Override
+ public SourceBuildOrPropertiesStep withoutKey() {
+ return new SourceBuildOrPropertiesStepImpl(relationshipType, relationship, relationshipKey, sourceBuilder);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceStepImpl.java
new file mode 100644
index 0000000..492264f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceStepImpl.java
@@ -0,0 +1,45 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.SourceStep;
+import org.onap.aai.champcore.model.fluent.relationship.SourceTypeOrFromStep;
+
+public final class SourceStepImpl implements SourceStep {
+
+ private final String relationshipType;
+ private final Object key;
+ private final ChampRelationship relationship;
+
+ public SourceStepImpl(String relationshipType, ChampRelationship relationship, Object key) {
+ this.relationshipType = relationshipType;
+ this.key = key;
+ this.relationship = relationship;
+ }
+
+ @Override
+ public SourceTypeOrFromStep withSource() {
+ return new SourceTypeOrFromStepImpl(relationshipType, relationship, key);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java
new file mode 100644
index 0000000..6ba248f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.SourceBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.SourceKeyStep;
+import org.onap.aai.champcore.model.fluent.relationship.SourceTypeOrFromStep;
+
+public final class SourceTypeOrFromStepImpl implements SourceTypeOrFromStep {
+
+ private final String relationshipType;
+ private final Object relationshipKey;
+ private final ChampRelationship relationship;
+
+ public SourceTypeOrFromStepImpl(String relationshipType, ChampRelationship relationship, Object key) {
+ this.relationshipType = relationshipType;
+ this.relationship = relationship;
+ this.relationshipKey = key;
+ }
+
+ @Override
+ public SourceKeyStep ofType(String type) {
+ final ChampObject.Builder sourceBuilder = new ChampObject.Builder(type);
+ return new SourceKeyStepImpl(relationshipType, relationship, relationshipKey, sourceBuilder);
+ }
+
+ @Override
+ public SourceBuildOrPropertiesStep from(ChampObject object) {
+ final ChampObject.Builder sourceBuilder = new ChampObject.Builder(object);
+ return new SourceBuildOrPropertiesStepImpl(relationshipType, relationship, relationshipKey, sourceBuilder);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java
new file mode 100644
index 0000000..1407703
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java
@@ -0,0 +1,65 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.RelationshipBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.TargetBuildOrPropertiesStep;
+
+public final class TargetBuildOrPropertiesStepImpl implements TargetBuildOrPropertiesStep {
+
+ private final String relationshipType;
+ private final ChampRelationship relationship;
+ private final Object relationshipKey;
+ private final ChampObject source;
+ private final ChampObject.Builder targetBuilder;
+
+ public TargetBuildOrPropertiesStepImpl(String relationshipType, ChampRelationship relationship, Object relationshipKey,
+ ChampObject source, ChampObject.Builder targetBuilder) {
+ this.relationshipType = relationshipType;
+ this.relationship = relationship;
+ this.relationshipKey = relationshipKey;
+ this.source = source;
+ this.targetBuilder = targetBuilder;
+ }
+
+ @Override
+ public TargetBuildOrPropertiesStep withProperty(String key, Object value) {
+ targetBuilder.property(key, value);
+ return this;
+ }
+
+ @Override
+ public RelationshipBuildOrPropertiesStep build() {
+
+ final ChampRelationship.Builder relationshipBuilder;
+
+ if (relationship != null) relationshipBuilder = new ChampRelationship.Builder(relationship);
+ else relationshipBuilder = new ChampRelationship.Builder(source, targetBuilder.build(), relationshipType);
+
+ if (relationshipKey != null) relationshipBuilder.key(relationshipKey);
+
+ return new RelationshipBuildOrPropertiesStepImpl(relationshipBuilder);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetKeyStepImpl.java
new file mode 100644
index 0000000..36e49a6
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetKeyStepImpl.java
@@ -0,0 +1,56 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.TargetBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.TargetKeyStep;
+
+public final class TargetKeyStepImpl implements TargetKeyStep {
+
+ private final String relationshipType;
+ private final Object relationshipKey;
+ private final ChampRelationship relationship;
+ private final ChampObject source;
+ private final ChampObject.Builder targetBuilder;
+
+ public TargetKeyStepImpl(String relationshipType, ChampRelationship relationship, Object key, ChampObject source, ChampObject.Builder targetBuilder) {
+ this.relationshipType = relationshipType;
+ this.relationship = relationship;
+ this.relationshipKey = key;
+ this.source = source;
+ this.targetBuilder = targetBuilder;
+ }
+
+ @Override
+ public TargetBuildOrPropertiesStep withKey(Object key) {
+ targetBuilder.key(key);
+ return new TargetBuildOrPropertiesStepImpl(relationshipType, relationship, relationshipKey, source, targetBuilder);
+ }
+
+ @Override
+ public TargetBuildOrPropertiesStep withoutKey() {
+ return new TargetBuildOrPropertiesStepImpl(relationshipType, relationship, relationshipKey, source, targetBuilder);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetStepImpl.java
new file mode 100644
index 0000000..0721fca
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetStepImpl.java
@@ -0,0 +1,49 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.TargetStep;
+import org.onap.aai.champcore.model.fluent.relationship.TargetTypeOrFromStep;
+
+public final class TargetStepImpl implements TargetStep {
+
+ private String relationshipType;
+ private ChampRelationship relationship;
+ private Object relationshipKey;
+ private ChampObject source;
+
+ public TargetStepImpl(String relationshipType, ChampRelationship relationship, Object relationshipKey,
+ ChampObject source) {
+ this.relationshipType = relationshipType;
+ this.relationship = relationship;
+ this.relationshipKey = relationshipKey;
+ this.source = source;
+ }
+
+ @Override
+ public TargetTypeOrFromStep withTarget() {
+ return new TargetTypeOrFromStepImpl(relationshipType, relationship, relationshipKey, source);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java
new file mode 100644
index 0000000..22d1d1d
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.relationship.impl;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.relationship.TargetBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.TargetKeyStep;
+import org.onap.aai.champcore.model.fluent.relationship.TargetTypeOrFromStep;
+
+public final class TargetTypeOrFromStepImpl implements TargetTypeOrFromStep {
+
+ private final String relationshipType;
+ private final Object relationshipKey;
+ private final ChampRelationship relationship;
+ private final ChampObject source;
+
+ public TargetTypeOrFromStepImpl(String relationshipType, ChampRelationship relationship, Object key, ChampObject source) {
+ this.relationshipType = relationshipType;
+ this.relationship = relationship;
+ this.relationshipKey = key;
+ this.source = source;
+ }
+
+ @Override
+ public TargetKeyStep ofType(String type) {
+ final ChampObject.Builder targetBuilder = new ChampObject.Builder(type);
+ return new TargetKeyStepImpl(relationshipType, relationship, relationshipKey, source, targetBuilder);
+ }
+
+ @Override
+ public TargetBuildOrPropertiesStep from(ChampObject object) {
+ final ChampObject.Builder targetBuilder = new ChampObject.Builder(object);
+ return new TargetBuildOrPropertiesStepImpl(relationshipType, relationship, relationshipKey, source, targetBuilder);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/CreateChampSchemable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/CreateChampSchemable.java
new file mode 100644
index 0000000..2e1b6d9
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/CreateChampSchemable.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface CreateChampSchemable extends BuildStep<ChampSchema> {
+
+ public ObjectConstraintTypeStep withObjectConstraint();
+ public RelationshipConstraintTypeStep withRelationshipConstraint();
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintBuildStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintBuildStep.java
new file mode 100644
index 0000000..57daae8
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintBuildStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface ObjectConstraintBuildStep extends BuildStep<ObjectConstraintPropertyStep> {
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldStep.java
new file mode 100644
index 0000000..06fd723
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface ObjectConstraintFieldStep {
+
+ public ObjectConstraintSubStep onField(String name);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldTypeStep.java
new file mode 100644
index 0000000..f17608e
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldTypeStep.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.ChampField;
+
+public interface ObjectConstraintFieldTypeStep {
+
+ public ObjectConstraintRequiredOptionalStep ofType(ChampField.Type type);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintPropertyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintPropertyStep.java
new file mode 100644
index 0000000..039e4d0
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintPropertyStep.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface ObjectConstraintPropertyStep extends BuildStep<CreateChampSchemable> {
+
+ public ObjectConstraintFieldStep withPropertyConstraint();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java
new file mode 100644
index 0000000..03353b5
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.ChampCardinality;
+
+public interface ObjectConstraintRequiredOptionalStep {
+
+ public ObjectConstraintBuildStep required();
+ public ObjectConstraintBuildStep optional();
+ public ObjectConstraintRequiredOptionalStep cardinality(ChampCardinality cardinality);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintSubStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintSubStep.java
new file mode 100644
index 0000000..eb9973f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintSubStep.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface ObjectConstraintSubStep extends ObjectConstraintFieldTypeStep, ObjectConstraintRequiredOptionalStep{
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintTypeStep.java
new file mode 100644
index 0000000..9ac2f1d
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintTypeStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface ObjectConstraintTypeStep {
+
+ public ObjectConstraintPropertyStep onType(String type);
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintBuildStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintBuildStep.java
new file mode 100644
index 0000000..669b829
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintBuildStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface RelationshipConstraintBuildStep extends BuildStep<RelationshipConstraintSubStep> {
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldStep.java
new file mode 100644
index 0000000..17a4bc6
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface RelationshipConstraintFieldStep {
+
+ public RelationshipConstraintPropertyOptionalsStep onField(String name);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldTypeStep.java
new file mode 100644
index 0000000..42b6edf
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldTypeStep.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.ChampField;
+
+public interface RelationshipConstraintFieldTypeStep {
+
+ public RelationshipConstraintRequiredOptionalStep ofType(ChampField.Type type);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintMultiplicityStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintMultiplicityStep.java
new file mode 100644
index 0000000..9b09a6c
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintMultiplicityStep.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.ChampConnectionMultiplicity;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface RelationshipConstraintMultiplicityStep extends BuildStep<RelationshipConstraintSubStep> {
+
+ public BuildStep<RelationshipConstraintSubStep> withMultiplicity(ChampConnectionMultiplicity multiplicity);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java
new file mode 100644
index 0000000..372c53f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java
@@ -0,0 +1,25 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface RelationshipConstraintPropertyOptionalsStep extends RelationshipConstraintFieldTypeStep, RelationshipConstraintRequiredOptionalStep {
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java
new file mode 100644
index 0000000..e8fb941
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface RelationshipConstraintRequiredOptionalStep {
+
+ public RelationshipConstraintBuildStep required();
+ public RelationshipConstraintBuildStep optional();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSourceStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSourceStep.java
new file mode 100644
index 0000000..0e7f62f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSourceStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface RelationshipConstraintSourceStep {
+
+ public RelationshipConstraintTargetStep sourcedFrom(String sourceType);
+ public RelationshipConstraintTargetStep sourcedFromAny();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSubStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSubStep.java
new file mode 100644
index 0000000..f27b2a4
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSubStep.java
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+import org.onap.aai.champcore.model.fluent.BuildStep;
+
+public interface RelationshipConstraintSubStep extends BuildStep<CreateChampSchemable> {
+
+ public RelationshipConstraintFieldStep withPropertyConstraint();
+ public RelationshipConstraintSourceStep withConnectionConstraint();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTargetStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTargetStep.java
new file mode 100644
index 0000000..b9ec7a2
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTargetStep.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface RelationshipConstraintTargetStep {
+
+ public RelationshipConstraintMultiplicityStep targetedTo(String targetType);
+ public RelationshipConstraintMultiplicityStep targetedToAny();
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTypeStep.java
new file mode 100644
index 0000000..f7a7c3f
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTypeStep.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema;
+
+public interface RelationshipConstraintTypeStep {
+
+ public RelationshipConstraintSubStep onType(String type);
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/CreateChampSchemableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/CreateChampSchemableImpl.java
new file mode 100644
index 0000000..217b55d
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/CreateChampSchemableImpl.java
@@ -0,0 +1,74 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.schema.CreateChampSchemable;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintPropertyStep;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintTypeStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintSubStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintTypeStep;
+
+public class CreateChampSchemableImpl implements CreateChampSchemable {
+
+ private final ChampSchema.Builder schemaBuilder;
+
+ public CreateChampSchemableImpl() {
+ this.schemaBuilder = new ChampSchema.Builder();
+ }
+
+ public CreateChampSchemableImpl(ChampSchema.Builder schemaBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ }
+
+ @Override
+ public ChampSchema build() {
+ return schemaBuilder.build();
+ }
+
+ @Override
+ public ObjectConstraintTypeStep withObjectConstraint() {
+ return new ObjectConstraintTypeStep() {
+
+ @Override
+ public ObjectConstraintPropertyStep onType(String type) {
+ return new ObjectConstraintPropertyStepImpl(schemaBuilder,
+ new ChampObjectConstraint.Builder(type));
+ }
+ };
+ }
+
+ @Override
+ public RelationshipConstraintTypeStep withRelationshipConstraint() {
+ return new RelationshipConstraintTypeStep() {
+
+ @Override
+ public RelationshipConstraintSubStep onType(String type) {
+ return new RelationshipConstraintSubStepImpl(schemaBuilder,
+ new ChampRelationshipConstraint.Builder(type));
+ }
+ };
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java
new file mode 100644
index 0000000..8933555
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintBuildStep;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintPropertyStep;
+
+public class ObjectConstraintBuildStepImpl implements ObjectConstraintBuildStep {
+
+ private final ChampSchema.Builder schemaBuilder;
+ private final ChampObjectConstraint.Builder constraintBuilder;
+
+ public ObjectConstraintBuildStepImpl(ChampSchema.Builder schemaBuilder, ChampObjectConstraint.Builder constraintBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ this.constraintBuilder = constraintBuilder;
+ }
+
+ @Override
+ public ObjectConstraintPropertyStep build() {
+ return new ObjectConstraintPropertyStepImpl(schemaBuilder, constraintBuilder);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java
new file mode 100644
index 0000000..f149769
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java
@@ -0,0 +1,45 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintFieldStep;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintSubStep;
+
+public class ObjectConstraintFieldStepImpl implements ObjectConstraintFieldStep {
+
+ private final ChampSchema.Builder schemaBuilder;
+ private final ChampObjectConstraint.Builder constraintBuilder;
+
+ public ObjectConstraintFieldStepImpl(ChampSchema.Builder schemaBuilder, ChampObjectConstraint.Builder constraintBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ this.constraintBuilder = constraintBuilder;
+ }
+
+ @Override
+ public ObjectConstraintSubStep onField(String name) {
+ return new ObjectConstraintSubStepImpl(schemaBuilder, constraintBuilder, new ChampField.Builder(name));
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java
new file mode 100644
index 0000000..c16d311
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java
@@ -0,0 +1,50 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.schema.CreateChampSchemable;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintFieldStep;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintPropertyStep;
+
+public class ObjectConstraintPropertyStepImpl implements ObjectConstraintPropertyStep {
+
+ private final ChampObjectConstraint.Builder constraintBuilder;
+ private final ChampSchema.Builder schemaBuilder;
+
+ public ObjectConstraintPropertyStepImpl(ChampSchema.Builder schemaBuilder, ChampObjectConstraint.Builder constraintBuilder) {
+ this.constraintBuilder = constraintBuilder;
+ this.schemaBuilder = schemaBuilder;
+ }
+
+ @Override
+ public CreateChampSchemable build() {
+ return new CreateChampSchemableImpl(schemaBuilder.constraint(constraintBuilder.build()));
+ }
+
+ @Override
+ public ObjectConstraintFieldStep withPropertyConstraint() {
+ return new ObjectConstraintFieldStepImpl(schemaBuilder, constraintBuilder);
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java
new file mode 100644
index 0000000..5cb13f3
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java
@@ -0,0 +1,111 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampCardinality;
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampPropertyConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintBuildStep;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintPropertyStep;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintRequiredOptionalStep;
+import org.onap.aai.champcore.model.fluent.schema.ObjectConstraintSubStep;
+
+public class ObjectConstraintSubStepImpl implements ObjectConstraintSubStep {
+
+ private final ChampSchema.Builder schemaBuilder;
+ private final ChampObjectConstraint.Builder constraintBuilder;
+ private final ChampField.Builder fieldBuilder;
+ private final ChampPropertyConstraint.Builder propConstBuilder;
+
+ public ObjectConstraintSubStepImpl(ChampSchema.Builder schemaBuilder,
+ ChampObjectConstraint.Builder constraintBuilder,
+ ChampField.Builder fieldBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ this.constraintBuilder = constraintBuilder;
+ this.fieldBuilder = fieldBuilder;
+ this.propConstBuilder = new ChampPropertyConstraint.Builder(fieldBuilder.build());
+
+ }
+
+ @Override
+ public ObjectConstraintRequiredOptionalStep ofType(ChampField.Type type) {
+ return new ObjectConstraintRequiredOptionalStep() {
+ final ChampPropertyConstraint.Builder propConstBuilder = new ChampPropertyConstraint.Builder(fieldBuilder.type(type).build());
+
+ @Override
+ public ObjectConstraintBuildStep required() {
+ constraintBuilder.constraint(propConstBuilder.required(true).build());
+
+ return new ObjectConstraintBuildStep() {
+
+ @Override
+ public ObjectConstraintPropertyStep build() {
+ return new ObjectConstraintPropertyStepImpl(schemaBuilder, constraintBuilder);
+ }
+ };
+ }
+
+ @Override
+ public ObjectConstraintBuildStep optional() {
+ constraintBuilder.constraint(propConstBuilder.required(false).build());
+
+ return new ObjectConstraintBuildStep() {
+
+ @Override
+ public ObjectConstraintPropertyStep build() {
+ return new ObjectConstraintPropertyStepImpl(schemaBuilder, constraintBuilder);
+ }
+ };
+ }
+
+ @Override
+ public ObjectConstraintRequiredOptionalStep cardinality(ChampCardinality cardinality) {
+ propConstBuilder.cardinality(cardinality);
+ return this;
+ }
+ };
+ }
+
+ @Override
+ public ObjectConstraintBuildStep required() {
+ constraintBuilder.constraint(propConstBuilder.required(true).build());
+
+ return new ObjectConstraintBuildStepImpl(schemaBuilder, constraintBuilder);
+ }
+
+ @Override
+ public ObjectConstraintBuildStep optional() {
+ final ChampPropertyConstraint.Builder propConstBuilder = new ChampPropertyConstraint.Builder(fieldBuilder.build());
+
+ constraintBuilder.constraint(propConstBuilder.required(false).build());
+
+ return new ObjectConstraintBuildStepImpl(schemaBuilder, constraintBuilder);
+ }
+
+ @Override
+ public ObjectConstraintRequiredOptionalStep cardinality(ChampCardinality cardinality) {
+ propConstBuilder.cardinality(cardinality);
+ return this;
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java
new file mode 100644
index 0000000..906dd4e
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java
@@ -0,0 +1,45 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.ChampSchema.Builder;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintBuildStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintSubStep;
+
+public class RelationshipConstraintBuildStepImpl implements RelationshipConstraintBuildStep {
+
+ private final ChampSchema.Builder schemaBuilder;
+ private final ChampRelationshipConstraint.Builder relConstraintBuilder;
+
+ public RelationshipConstraintBuildStepImpl(Builder schemaBuilder,
+ ChampRelationshipConstraint.Builder relConstraintBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ this.relConstraintBuilder = relConstraintBuilder;
+ }
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ return new RelationshipConstraintSubStepImpl(schemaBuilder, relConstraintBuilder);
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java
new file mode 100644
index 0000000..ba39d61
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampPropertyConstraint;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintBuildStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintPropertyOptionalsStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintRequiredOptionalStep;
+
+public class RelationshipConstraintPropertyOptionalsStepImpl implements RelationshipConstraintPropertyOptionalsStep {
+
+ private final ChampSchema.Builder schemaBuilder;
+ private final ChampRelationshipConstraint.Builder relConstraintBuilder;
+ private final ChampField.Builder fieldBuilder;
+
+ public RelationshipConstraintPropertyOptionalsStepImpl(ChampSchema.Builder schemaBuilder,
+ ChampRelationshipConstraint.Builder relConstraintBuilder,
+ ChampField.Builder fieldBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ this.relConstraintBuilder = relConstraintBuilder;
+ this.fieldBuilder = fieldBuilder;
+ }
+
+ @Override
+ public RelationshipConstraintRequiredOptionalStep ofType(ChampField.Type type) {
+ return new RelationshipConstraintRequiredOptionalStepImpl(schemaBuilder, relConstraintBuilder, fieldBuilder.type(type));
+ }
+
+ @Override
+ public RelationshipConstraintBuildStep required() {
+ final ChampPropertyConstraint propConstraint = new ChampPropertyConstraint.Builder(fieldBuilder.build())
+ .required(true)
+ .build();
+
+ return new RelationshipConstraintBuildStepImpl(schemaBuilder, relConstraintBuilder.constraint(propConstraint));
+ }
+
+ @Override
+ public RelationshipConstraintBuildStep optional() {
+ final ChampPropertyConstraint propConstraint = new ChampPropertyConstraint.Builder(fieldBuilder.build())
+ .required(false)
+ .build();
+
+ return new RelationshipConstraintBuildStepImpl(schemaBuilder, relConstraintBuilder.constraint(propConstraint));
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java
new file mode 100644
index 0000000..8a760d1
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java
@@ -0,0 +1,64 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampPropertyConstraint;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.ChampSchema.Builder;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintBuildStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintRequiredOptionalStep;
+
+public class RelationshipConstraintRequiredOptionalStepImpl implements RelationshipConstraintRequiredOptionalStep {
+
+ private final ChampSchema.Builder schemaBuilder;
+ private final ChampRelationshipConstraint.Builder relConstraintBuilder;
+ private final ChampField.Builder fieldBuilder;
+
+ public RelationshipConstraintRequiredOptionalStepImpl(Builder schemaBuilder,
+ ChampRelationshipConstraint.Builder relConstraintBuilder,
+ ChampField.Builder fieldBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ this.relConstraintBuilder = relConstraintBuilder;
+ this.fieldBuilder = fieldBuilder;
+ }
+
+ @Override
+ public RelationshipConstraintBuildStep required() {
+ final ChampPropertyConstraint propConstraint = new ChampPropertyConstraint.Builder(fieldBuilder.build())
+ .required(true)
+ .build();
+
+ return new RelationshipConstraintBuildStepImpl(schemaBuilder, relConstraintBuilder.constraint(propConstraint));
+ }
+
+ @Override
+ public RelationshipConstraintBuildStep optional() {
+ final ChampPropertyConstraint propConstraint = new ChampPropertyConstraint.Builder(fieldBuilder.build())
+ .required(false)
+ .build();
+
+ return new RelationshipConstraintBuildStepImpl(schemaBuilder, relConstraintBuilder.constraint(propConstraint));
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java
new file mode 100644
index 0000000..6df9cff
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java
@@ -0,0 +1,205 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.model.fluent.schema.impl;
+
+import org.onap.aai.champcore.model.ChampConnectionConstraint;
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampConnectionMultiplicity;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.model.fluent.BuildStep;
+import org.onap.aai.champcore.model.fluent.schema.CreateChampSchemable;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintFieldStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintMultiplicityStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintPropertyOptionalsStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintSourceStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintSubStep;
+import org.onap.aai.champcore.model.fluent.schema.RelationshipConstraintTargetStep;
+
+public class RelationshipConstraintSubStepImpl implements RelationshipConstraintSubStep {
+
+ private final ChampSchema.Builder schemaBuilder;
+ private final ChampRelationshipConstraint.Builder relConstraintBuilder;
+
+ public RelationshipConstraintSubStepImpl(ChampSchema.Builder schemaBuilder,
+ ChampRelationshipConstraint.Builder relConstraintBuilder) {
+ this.schemaBuilder = schemaBuilder;
+ this.relConstraintBuilder = relConstraintBuilder;
+ }
+
+ @Override
+ public CreateChampSchemable build() {
+ return new CreateChampSchemableImpl(schemaBuilder.constraint(relConstraintBuilder.build()));
+ }
+
+ @Override
+ public RelationshipConstraintFieldStep withPropertyConstraint() {
+ return new RelationshipConstraintFieldStep() {
+
+ @Override
+ public RelationshipConstraintPropertyOptionalsStep onField(String name) {
+ return new RelationshipConstraintPropertyOptionalsStepImpl(schemaBuilder, relConstraintBuilder, new ChampField.Builder(name));
+ }
+ };
+ }
+
+ @Override
+ public RelationshipConstraintSourceStep withConnectionConstraint() {
+ return new RelationshipConstraintSourceStep() {
+
+ @Override
+ public RelationshipConstraintTargetStep sourcedFrom(String sourceType) {
+
+ return new RelationshipConstraintTargetStep() {
+
+ @Override
+ public RelationshipConstraintMultiplicityStep targetedTo(String targetType) {
+ final ChampConnectionConstraint.Builder connectionConstraint = new ChampConnectionConstraint.Builder(sourceType, targetType);
+
+ return new RelationshipConstraintMultiplicityStep() {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+
+ @Override
+ public BuildStep<RelationshipConstraintSubStep> withMultiplicity(
+ ChampConnectionMultiplicity multiplicity) {
+ connectionConstraint.multiplicity(multiplicity);
+ return new BuildStep<RelationshipConstraintSubStep> () {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public RelationshipConstraintMultiplicityStep targetedToAny() {
+ final ChampConnectionConstraint.Builder connectionConstraint = new ChampConnectionConstraint.Builder(sourceType, ChampObject.ReservedTypes.ANY.toString());
+
+ return new RelationshipConstraintMultiplicityStep() {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+
+ @Override
+ public BuildStep<RelationshipConstraintSubStep> withMultiplicity(
+ ChampConnectionMultiplicity multiplicity) {
+ connectionConstraint.multiplicity(multiplicity);
+ return new BuildStep<RelationshipConstraintSubStep> () {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public RelationshipConstraintTargetStep sourcedFromAny() {
+ return new RelationshipConstraintTargetStep() {
+
+ @Override
+ public RelationshipConstraintMultiplicityStep targetedTo(String targetType) {
+ final ChampConnectionConstraint.Builder connectionConstraint = new ChampConnectionConstraint.Builder(ChampObject.ReservedTypes.ANY.toString(), targetType);
+
+ return new RelationshipConstraintMultiplicityStep() {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+
+ @Override
+ public BuildStep<RelationshipConstraintSubStep> withMultiplicity(
+ ChampConnectionMultiplicity multiplicity) {
+ connectionConstraint.multiplicity(multiplicity);
+ return new BuildStep<RelationshipConstraintSubStep> () {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public RelationshipConstraintMultiplicityStep targetedToAny() {
+ final ChampConnectionConstraint.Builder connectionConstraint = new ChampConnectionConstraint.Builder(ChampObject.ReservedTypes.ANY.toString(), ChampObject.ReservedTypes.ANY.toString());
+
+ return new RelationshipConstraintMultiplicityStep() {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+
+ @Override
+ public BuildStep<RelationshipConstraintSubStep> withMultiplicity(
+ ChampConnectionMultiplicity multiplicity) {
+ connectionConstraint.multiplicity(multiplicity);
+ return new BuildStep<RelationshipConstraintSubStep> () {
+
+ @Override
+ public RelationshipConstraintSubStep build() {
+ relConstraintBuilder.constraint(connectionConstraint.build());
+
+ return RelationshipConstraintSubStepImpl.this;
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/AlwaysValidChampSchemaEnforcer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/AlwaysValidChampSchemaEnforcer.java
new file mode 100644
index 0000000..6aa62a4
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/AlwaysValidChampSchemaEnforcer.java
@@ -0,0 +1,45 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.schema;
+
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+
+public final class AlwaysValidChampSchemaEnforcer implements ChampSchemaEnforcer {
+
+ @Override
+ public void validate(ChampObject champObject, ChampObjectConstraint champObjectConstraint) {
+ }
+
+ @Override
+ public void validate(ChampRelationship champRelationship,
+ ChampRelationshipConstraint champRelationshipConstraint) {
+ }
+
+ @Override
+ public void validate(ChampPartition champPartition, ChampSchema schema) {
+ }
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/ChampSchemaEnforcer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/ChampSchemaEnforcer.java
new file mode 100644
index 0000000..5113aa2
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/ChampSchemaEnforcer.java
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.schema;
+
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+
+public interface ChampSchemaEnforcer {
+
+ public void validate(ChampObject champObject, ChampObjectConstraint champObjectConstraint) throws ChampSchemaViolationException;
+ public void validate(ChampRelationship champRelationship, ChampRelationshipConstraint champRelationshipConstraint) throws ChampSchemaViolationException;
+ public void validate(ChampPartition champPartition, ChampSchema schema) throws ChampSchemaViolationException;
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/DefaultChampSchemaEnforcer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/DefaultChampSchemaEnforcer.java
new file mode 100644
index 0000000..308244e
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/DefaultChampSchemaEnforcer.java
@@ -0,0 +1,144 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.schema;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.model.ChampConnectionConstraint;
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampPropertyConstraint;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+
+public final class DefaultChampSchemaEnforcer implements ChampSchemaEnforcer {
+
+ @Override
+ public void validate(ChampObject champObject, ChampObjectConstraint champObjectConstraint) throws ChampSchemaViolationException {
+ for (ChampPropertyConstraint pc : champObjectConstraint.getPropertyConstraints()) {
+ final ChampField field = pc.getField();
+ final Optional<Object> property = champObject.getProperty(field.getName());
+
+ if (pc.isRequired() && !property.isPresent()) {
+ throw new ChampSchemaViolationException("Required property " + pc.getField().getName() + " is not present");
+ }
+
+ if (property.isPresent()) {
+ switch (pc.getCardinality()) {
+ case SINGLE:
+ if (!pc.getField().getJavaType().isInstance(property.get())) {
+ throw new ChampSchemaViolationException("Expected type " + pc.getField().getType() + " for type " + pc.getField().getName());
+ }
+ break;
+ case LIST:
+ if (!(property.get() instanceof List)) throw new ChampSchemaViolationException("Expected List type for ChampCardinality." + pc.getCardinality());
+ break;
+ case SET:
+ if (!(property.get() instanceof Set)) throw new ChampSchemaViolationException("Expected Set type for ChampCardinality." + pc.getCardinality());
+ break;
+ default:
+ throw new RuntimeException("Unknown property constraint cardinality " + pc.getCardinality());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void validate(ChampRelationship champRelationship,
+ ChampRelationshipConstraint champRelationshipConstraint) throws ChampSchemaViolationException {
+
+ for (ChampPropertyConstraint pc : champRelationshipConstraint.getPropertyConstraints()) {
+ final ChampField field = pc.getField();
+ final Optional<Object> property = champRelationship.getProperty(field.getName());
+
+ if (pc.isRequired() && !property.isPresent()) {
+ throw new ChampSchemaViolationException("Required property " + pc.getField().getName() + " is not present");
+ }
+
+ if (property.isPresent() && !pc.getField().getJavaType().isInstance(property.get())) {
+ throw new ChampSchemaViolationException("Expected type " + pc.getField().getType() + " for type " + pc.getField().getName());
+ }
+ }
+ }
+
+ @Override
+ public void validate(ChampPartition champPartition, ChampSchema schema) throws ChampSchemaViolationException {
+
+ for (ChampObject object : champPartition.getChampObjects()) {
+ final Optional<ChampObjectConstraint> objConstraint = schema.getObjectConstraint(object.getType());
+
+ if (!objConstraint.isPresent()) continue;
+
+ validate(object, objConstraint.get());
+
+ final Map<String, Set<ChampRelationship>> incidentRelationshipsByType = champPartition.getIncidentRelationshipsByType(object);
+
+ for (Map.Entry<String, Set<ChampRelationship>> incidentRelationshipsOfType : incidentRelationshipsByType.entrySet()) {
+ final Optional<ChampRelationshipConstraint> relConstraint = schema.getRelationshipConstraint(incidentRelationshipsOfType.getKey());
+
+ if (relConstraint.isPresent()) {
+ final ChampRelationshipConstraint relationshipConstraint = relConstraint.get();
+ final Map<ChampConnectionConstraint, AtomicInteger> connectionCounts = new HashMap<ChampConnectionConstraint, AtomicInteger> ();
+
+ for (ChampRelationship incidentRelationship : incidentRelationshipsOfType.getValue()) {
+ final Optional<ChampConnectionConstraint> connectionConstraint = relationshipConstraint.getConnectionConstraint(incidentRelationship);
+
+ validate(incidentRelationship, relationshipConstraint);
+
+ if (connectionConstraint.isPresent()) {
+
+ if (!connectionCounts.containsKey(connectionConstraint.get())) {
+ connectionCounts.put(connectionConstraint.get(), new AtomicInteger(0));
+ }
+
+ final int connectionCount = connectionCounts.get(connectionConstraint.get()).incrementAndGet();
+
+ switch (connectionConstraint.get().getMultiplicity()) {
+ case MANY:
+ //Always valid
+ break;
+ case NONE:
+ if (connectionCount > 0) throw new ChampSchemaViolationException("Violated connection constraint " + connectionConstraint.get());
+ break;
+ case ONE:
+ if (connectionCount > 1) throw new ChampSchemaViolationException("Violated connection constraint " + connectionConstraint.get());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/Champformer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/Champformer.java
new file mode 100644
index 0000000..e07ac14
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/Champformer.java
@@ -0,0 +1,34 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.transform;
+
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+
+public interface Champformer<V, E> {
+ public V marshallObject(ChampObject object) throws ChampUnmarshallingException;
+ public E marshallRelationship(ChampRelationship relationship) throws ChampUnmarshallingException;
+
+ public ChampObject unmarshallObject(V data) throws ChampUnmarshallingException;
+ public ChampRelationship unmarshallRelationship(E data) throws ChampUnmarshallingException;
+}
diff --git a/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/TinkerpopChampformer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/TinkerpopChampformer.java
new file mode 100644
index 0000000..8552cc6
--- /dev/null
+++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/TinkerpopChampformer.java
@@ -0,0 +1,94 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.transform;
+
+import java.util.Iterator;
+
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep;
+import org.onap.aai.champcore.model.fluent.relationship.RelationshipBuildOrPropertiesStep;
+
+public final class TinkerpopChampformer implements Champformer<Vertex, Edge> {
+
+ @Override
+ public Vertex marshallObject(ChampObject object) throws ChampUnmarshallingException {
+ throw new UnsupportedOperationException("Cannot marshall object to Tinkerpop Vertex without adding it to a graph");
+ }
+
+ @Override
+ public Edge marshallRelationship(ChampRelationship relationship) throws ChampUnmarshallingException {
+ throw new UnsupportedOperationException("Cannot marshall relationships to Tinkerpop Edge without adding it to a graph");
+ }
+
+ @Override
+ public ChampObject unmarshallObject(Vertex vertex) throws ChampUnmarshallingException {
+ final String type = vertex.label();
+ final ObjectBuildOrPropertiesStep aaiObjBuilder = ChampObject.create()
+ .ofType(type)
+ .withKey(vertex.id());
+ final Iterator<VertexProperty<Object>> properties = vertex.properties();
+
+ while (properties.hasNext()) {
+ final VertexProperty<Object> property = properties.next();
+
+ if (ChampObject.ReservedPropertyKeys.contains(property.key()) ||
+ ChampObject.IgnoreOnReadPropertyKeys.contains(property.key())) continue;
+
+ aaiObjBuilder.withProperty(property.key(), property.value());
+ }
+
+ return aaiObjBuilder.build();
+ }
+
+ @Override
+ public ChampRelationship unmarshallRelationship(Edge edge) throws ChampUnmarshallingException {
+ final ChampObject source = unmarshallObject(edge.outVertex());
+ final ChampObject target = unmarshallObject(edge.inVertex());
+ final String type = edge.label();
+ final RelationshipBuildOrPropertiesStep aaiRelBuilder = ChampRelationship.create()
+ .ofType(type)
+ .withKey(edge.id())
+ .withSource()
+ .from(source)
+ .build()
+ .withTarget()
+ .from(target)
+ .build();
+ final Iterator<Property<Object>> properties = edge.properties();
+
+ while (properties.hasNext()) {
+ final Property<Object> property = properties.next();
+
+ if (ChampRelationship.ReservedPropertyKeys.contains(property.key())) continue;
+
+ aaiRelBuilder.withProperty(property.key(), property.value());
+ }
+
+ return aaiRelBuilder.build();
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/concurrency/ConcurrencyTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/concurrency/ConcurrencyTest.java
new file mode 100644
index 0000000..9f9be02
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/concurrency/ConcurrencyTest.java
@@ -0,0 +1,74 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.concurrency;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.core.ChampObjectTest;
+import org.onap.aai.champcore.core.ChampRelationshipTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class ConcurrencyTest {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrencyTest.class);
+
+ @Test
+ public void runInMemoryConcurrentTest() {
+ runConcurrentTest("IN_MEMORY");
+ }
+
+ public void runConcurrentTest(String apiType) {
+ final ChampAPI api = ChampAPI.Factory.newInstance(apiType);
+ runConcurrencyTest(api);
+ api.shutdown();
+ }
+
+ private void runConcurrencyTest(ChampAPI api) {
+ final int numThreads = 10;
+ final ExecutorService es = Executors.newFixedThreadPool(numThreads);
+
+ for (int i = 0; i < numThreads * 2; i++) {
+ es.submit(new Runnable() {
+ @Override
+ public void run() {
+ final ChampGraph graph = api.getGraph(ConcurrencyTest.class.getSimpleName());
+ ChampObjectTest.testChampObjectCrud(graph);
+ ChampRelationshipTest.testChampRelationshipCrud(graph);
+ }
+ });
+ }
+
+ try {
+ es.shutdown();
+ es.awaitTermination(60, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Interrupted while waiting for concurrency test to finish", e);
+ return;
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/BaseChampAPITest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/BaseChampAPITest.java
new file mode 100644
index 0000000..229e920
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/BaseChampAPITest.java
@@ -0,0 +1,34 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BaseChampAPITest {
+
+ protected static final Logger LOGGER = LoggerFactory.getLogger(BaseChampAPITest.class);
+
+ protected static void cleanUp(String graphName) {
+ LOGGER.warn("cleanUp is disabled for unit tests - you can enable it by commenting out the code below this log message, please don't commit it though");
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampAPITest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampAPITest.java
new file mode 100644
index 0000000..f033b30
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampAPITest.java
@@ -0,0 +1,242 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.graph.impl.ChampAPIImpl;
+import org.onap.aai.champcore.graph.impl.InMemoryChampGraphImpl;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Optional;
+
+public class ChampAPITest {
+
+ @Test
+ public void testChampAPIMemoryInstantiation() {
+ testChampAPIInstantiation(new ChampAPIImpl("IN_MEMORY"), "IN_MEMORY");
+ }
+
+ public void testChampAPIInstantiation(ChampAPI api, String expectedType) {
+ assertTrue(api.getType() == expectedType);
+
+ api.getGraph("foo");
+ api.shutdown();
+
+ try {
+ api.getGraph("foo");
+ throw new AssertionError("Able to call getGraph(String name) after shutdown()");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+ }
+
+ @Test
+ public void testChampMemoryGraphInstantiation() throws Exception
+ {
+ testChampGraphInstantiation(new InMemoryChampGraphImpl.Builder().build());
+ }
+
+ public void testChampGraphInstantiation(ChampGraph graph) throws Exception {
+
+ graph.shutdown();
+
+ try {
+ graph.deleteObject(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.deleteObjectIndex(null);
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.deletePartition(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.deleteRelationship(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.deleteRelationshipIndex(null);
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.deleteSchema();
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.queryObjects(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.queryRelationships(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveObject(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveObjectIndex(null);
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveObjectIndices();
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveRelationship(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveRelationshipIndex(null);
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveRelationshipIndices();
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveRelationships(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.retrieveSchema();
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.storeObject(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.storeObjectIndex(null);
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.storePartition(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.storeRelationship(null, Optional.empty());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.storeRelationshipIndex(null);
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.storeSchema(null);
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.updateSchema(new ChampObjectConstraint.Builder("").build());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.updateSchema(new ChampRelationshipConstraint.Builder("").build());
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+
+ try {
+ graph.shutdown();
+ throw new AssertionError("Able to call API method after shutdown was initiated");
+ } catch (IllegalStateException e) {
+ //Expected
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampElementTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampElementTest.java
new file mode 100644
index 0000000..9eb5dfe
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampElementTest.java
@@ -0,0 +1,62 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.aai.champcore.model.ChampElement;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+
+public class ChampElementTest {
+
+ @Test
+ public void testChampElement() {
+ final ChampElement fooElement = new ChampObject.Builder("foo").build();
+
+ assertTrue(fooElement.isObject());
+ assertTrue(!fooElement.isRelationship());
+ assertTrue(fooElement.asObject() instanceof ChampObject);
+
+ try {
+ fooElement.asRelationship();
+ throw new AssertionError("Failed to throw exception when calling asRelationship() on a ChampObject");
+ } catch (UnsupportedOperationException e) {
+ //Expected
+ }
+
+ final ChampElement barElement = new ChampObject.Builder("bar").build();
+ final ChampElement usesElement = new ChampRelationship.Builder(fooElement.asObject(), barElement.asObject(), "uses").build();
+
+ assertTrue(usesElement.isRelationship());
+ assertTrue(!usesElement.isObject());
+ assertTrue(usesElement.asRelationship() instanceof ChampRelationship);
+
+ try {
+ usesElement.asObject();
+ throw new AssertionError("Failed to throw exception when calling asObject() on a ChampRelationship");
+ } catch (UnsupportedOperationException e) {
+ //Expected
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampFieldTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampFieldTest.java
new file mode 100644
index 0000000..4975739
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampFieldTest.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.aai.champcore.model.ChampField;
+
+public class ChampFieldTest {
+
+ @Test
+ public void testChampField() {
+ final ChampField a = new ChampField.Builder("a")
+ .type(ChampField.Type.STRING)
+ .build();
+
+ final ChampField aEquivalent = new ChampField.Builder("a")
+ .build();
+
+ final ChampField b = new ChampField.Builder("b")
+ .build();
+
+ assertTrue(a.equals(aEquivalent));
+ assertTrue(!a.equals(new Object()));
+ assertTrue(!a.equals(b));
+
+ assertTrue(a.compareTo(aEquivalent) == 0);
+ assertTrue(a.compareTo(b) != 0);
+
+ assertTrue(a.toString().equals(aEquivalent.toString()));
+ assertTrue(!a.toString().equals(b.toString()));
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectIndexTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectIndexTest.java
new file mode 100644
index 0000000..bb2c65e
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectIndexTest.java
@@ -0,0 +1,134 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+
+public class ChampObjectIndexTest extends BaseChampAPITest {
+ @Test
+ public void runTestMemory() {
+ runTest("IN_MEMORY");
+ }
+
+ public void runTest(String apiType) {
+ final ChampAPI api = ChampAPI.Factory.newInstance(apiType);
+ final String graphName = api.getClass().getSimpleName();
+
+ ChampObjectIndexTest.testChampObjectIndexCrud(api.getGraph(graphName));
+
+ api.shutdown();
+ }
+
+ public static void testChampObjectIndexCrud(ChampGraph graph) {
+
+ final ChampObjectIndex objectIndex = ChampObjectIndex.create()
+ .ofName("fooObjectIndex")
+ .onType("foo")
+ .forField("propertyName")
+ .build();
+
+ testChampObjectIndexStorage(graph, objectIndex);
+ testChampObjectIndexDelete(graph, objectIndex);
+ }
+
+ private static void testChampObjectIndexDelete(ChampGraph graph, ChampObjectIndex objectIndex) {
+
+ if (!graph.capabilities().canDeleteObjectIndices()) {
+ try {
+ graph.deleteObjectIndex("someindex");
+ throw new AssertionError("Graph claims it does not support object index delete, but failed to throw UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ } catch (ChampIndexNotExistsException e) {
+ throw new AssertionError("Graph claims it does not support object index delete, but failed to throw UnsupportedOperationException");
+ }
+ } else {
+ try {
+ graph.deleteObjectIndex(objectIndex.getName());
+
+ final Optional<ChampObjectIndex> retrievedObjectIndex = graph.retrieveObjectIndex(objectIndex.getName());
+
+ if (retrievedObjectIndex.isPresent()) throw new AssertionError("Retrieved object index after deleting it");
+
+ final Stream<ChampObjectIndex> retrievedObjectIndices = graph.retrieveObjectIndices();
+ final Collection<ChampObjectIndex> allObjectIndices = retrievedObjectIndices.collect(Collectors.toList());
+
+ if (allObjectIndices.contains(objectIndex)) throw new AssertionError("Retrieve all indices contained index previously deleted");
+ if (allObjectIndices.size() != 0) throw new AssertionError("Wrong number of indices returned by retrieve all indices");
+
+ } catch (ChampIndexNotExistsException e) {
+ throw new AssertionError(e);
+ }
+
+ try {
+ graph.deleteObjectIndex(objectIndex.getName());
+ throw new AssertionError("Failed to throw exception on non-existent object index");
+ } catch (ChampIndexNotExistsException e) {
+ //Expected
+ }
+ }
+ }
+
+ private static void testChampObjectIndexStorage(ChampGraph graph, ChampObjectIndex objectIndex) {
+
+ graph.storeObjectIndex(objectIndex);
+ graph.storeObjectIndex(objectIndex); //Test storing an already existing object index
+
+ assertTrue(!graph.retrieveRelationshipIndex(objectIndex.getName()).isPresent()); //Make sure this wasn't stored as an object index
+
+ final Optional<ChampObjectIndex> retrieveObjectIndex = graph.retrieveObjectIndex(objectIndex.getName());
+
+ if (!retrieveObjectIndex.isPresent()) throw new AssertionError("Failed to retrieve object index after storing it");
+ if (!objectIndex.equals(retrieveObjectIndex.get())) throw new AssertionError("Non-equal object index returned from API after storing it");
+
+ final Stream<ChampObjectIndex> retrievedObjectIndices = graph.retrieveObjectIndices();
+ final Collection<ChampObjectIndex> allObjectIndices = retrievedObjectIndices.collect(Collectors.toList());
+
+ if (!allObjectIndices.contains(objectIndex)) throw new AssertionError("Retrieve all indices did not contained index previously stored");
+ if (allObjectIndices.size() != 1) throw new AssertionError("Wrong number of indices returned by retrieve all indices");
+
+ assertTrue(!graph.retrieveObjectIndex("nonExistentIndexName").isPresent());
+ }
+
+ @Test
+ public void testFluentRelationshipCreation() {
+ final ChampObjectIndex objectIndex = ChampObjectIndex.create()
+ .ofName("fooNameIndex")
+ .onType("foo")
+ .forField("name")
+ .build();
+
+ assertTrue(objectIndex.getName().equals("fooNameIndex"));
+ assertTrue(objectIndex.getType().equals("foo"));
+ assertTrue(objectIndex.getField().getName().equals("name"));
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectTest.java
new file mode 100644
index 0000000..3ef8f8c
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectTest.java
@@ -0,0 +1,359 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampCapabilities;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.core.ChampRelationshipTest.TestTransaction;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.graph.impl.InMemoryChampGraphImpl;
+import org.onap.aai.champcore.model.ChampCardinality;
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampSchema;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertTrue;
+
+public class ChampObjectTest extends BaseChampAPITest {
+
+ @Test
+ public void testHashCode() {
+ final ChampObject foo1 = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("property", "value")
+ .withProperty("prop", 1)
+ .build();
+
+ final ChampObject foo2 = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("property", "value")
+ .withProperty("prop", 1)
+ .build();
+
+ final ChampObject foo1Copy = ChampObject.create()
+ .from(foo1)
+ .withoutKey()
+ .build();
+
+ final ChampObject foo2Copy = ChampObject.create()
+ .from(foo2)
+ .withoutKey()
+ .build();
+
+ assertTrue(foo1.hashCode() == foo2.hashCode());
+ assertTrue(foo1.hashCode() == foo1.hashCode());
+ assertTrue(foo2.hashCode() == foo2.hashCode());
+ assertTrue(foo1.hashCode() == foo1Copy.hashCode());
+ assertTrue(foo2.hashCode() == foo2Copy.hashCode());
+
+ assertTrue(Collections.singleton(foo1).contains(foo1));
+ assertTrue(Collections.singleton(foo1).contains(foo1Copy));
+ }
+
+ @Test
+ public void runInMemoryTest() {
+ runTest("IN_MEMORY");
+ }
+
+ public void runTest(String apiType) {
+ final String graphName = ChampObjectTest.class.getSimpleName();
+
+ final ChampAPI api = ChampAPI.Factory.newInstance(apiType);
+ ChampObjectTest.testChampObjectCrud(api.getGraph(graphName));
+ testChampObjectReservedProperties(api.getGraph(graphName));
+ api.shutdown();
+ }
+
+ public static void testChampObjectCrud(ChampGraph graph) {
+
+ // Create a dummy object...
+ final ChampObject bookooObject = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("property1", "value1")
+ .withProperty("integer", 1)
+ .withProperty("long", 1L)
+ .withProperty("double", 1.2)
+ .withProperty("float", 2.3F)
+ .withProperty("string", "foo")
+ .withProperty("boolean", true)
+ .withProperty("list", Collections.singletonList("list"))
+ .withProperty("set", Collections.singleton("set"))
+ .build();
+
+ final ChampObject storedBookooObject;
+
+ try {
+
+ // Create a schema for the graph.
+ graph.storeSchema(ChampSchema.create()
+ .withObjectConstraint()
+ .onType("foo")
+ .withPropertyConstraint()
+ .onField("list")
+ .ofType(ChampField.Type.STRING)
+ .cardinality(ChampCardinality.LIST)
+ .optional()
+ .build()
+ .withPropertyConstraint()
+ .onField("set")
+ .ofType(ChampField.Type.STRING)
+ .cardinality(ChampCardinality.SET)
+ .optional()
+ .build()
+ .build()
+ .build());
+
+
+
+ // Store the object in the graph.
+ storedBookooObject = graph.storeObject(bookooObject, Optional.empty());
+
+ // Check that the object we got back from the store call matches what we sent.
+ assertTrue(storedBookooObject.getProperty("property1").get().equals("value1"));
+ assertTrue(storedBookooObject.getProperty("integer").get().equals(1));
+ assertTrue(storedBookooObject.getProperty("long").get().equals(1L));
+ assertTrue(storedBookooObject.getProperty("double").get().equals(1.2));
+ assertTrue(storedBookooObject.getProperty("float").get().equals(2.3F));
+ assertTrue(storedBookooObject.getProperty("string").get().equals("foo"));
+ assertTrue(storedBookooObject.getProperty("boolean").get().equals(true));
+ assertTrue(storedBookooObject.getProperty("list").get().equals(Collections.singletonList("list")));
+ assertTrue(storedBookooObject.getProperty("set").get().equals(Collections.singleton("set")));
+
+ final Optional<ChampObject> retrievedBookooObject = graph.retrieveObject(storedBookooObject.getKey().get(), Optional.empty());
+
+ final Stream<ChampObject> emptyStream = graph.queryObjects(new HashMap<String, Object>() {{
+ put(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString(), "foo");
+ put("long", 2L);
+ }}, Optional.empty());
+
+ assertTrue(emptyStream.limit(1).count() == 0);
+
+ final Stream<ChampObject> oneStream = graph.queryObjects(new HashMap<String, Object>() {{
+ put(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString(), "foo");
+ put("long", 1L);
+ }}, Optional.empty());
+ final List<ChampObject> oneObject = oneStream.limit(2).collect(Collectors.toList());
+ assertTrue(oneObject.size() == 1);
+ assertTrue(oneObject.get(0).equals(storedBookooObject));
+
+ final List<ChampObject> queryByKey = graph.queryObjects(Collections.singletonMap(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString(), storedBookooObject.getKey().get()), Optional.empty())
+ .limit(2)
+ .collect(Collectors.toList());
+
+ assertTrue(queryByKey.size() == 1);
+ assertTrue(queryByKey.get(0).equals(storedBookooObject));
+
+ if (!retrievedBookooObject.isPresent()) {
+ throw new AssertionError("Failed to retrieve stored object " + bookooObject);
+ }
+ if (!storedBookooObject.equals(retrievedBookooObject.get())) {
+ throw new AssertionError("Retrieved object does not equal stored object");
+ }
+
+ final ChampObject updatedBookoo = graph.storeObject(ChampObject.create()
+ .from(storedBookooObject)
+ .withKey(storedBookooObject.getKey().get())
+ .withProperty("long", 2L)
+ .build(), Optional.empty());
+
+ final Optional<ChampObject> retrievedUpdBookooObject = graph.retrieveObject(updatedBookoo.getKey().get(), Optional.empty());
+
+ assertTrue(updatedBookoo.getProperty("property1").get().equals("value1"));
+ assertTrue(updatedBookoo.getProperty("integer").get().equals(1));
+ assertTrue(updatedBookoo.getProperty("long").get().equals(2L));
+ assertTrue(updatedBookoo.getProperty("double").get().equals(1.2));
+ assertTrue(updatedBookoo.getProperty("float").get().equals(2.3F));
+ assertTrue(updatedBookoo.getProperty("string").get().equals("foo"));
+ assertTrue(updatedBookoo.getProperty("boolean").get().equals(true));
+ assertTrue(updatedBookoo.getProperty("list").get().equals(Collections.singletonList("list")));
+ assertTrue(updatedBookoo.getProperty("set").get().equals(Collections.singleton("set")));
+
+ if (!retrievedUpdBookooObject.isPresent()) {
+ throw new AssertionError("Failed to retrieve stored object " + bookooObject);
+ }
+ if (!updatedBookoo.equals(retrievedUpdBookooObject.get())) {
+ throw new AssertionError("Retrieved object does not equal stored object");
+ }
+
+ //validate the replaceObject method
+ final ChampObject replacedBookoo = graph.replaceObject(ChampObject.create()
+ .ofType("foo")
+ .withKey(storedBookooObject.getKey().get())
+ .withProperty("property1", "value2")
+ .withProperty("list", Collections.singletonList("list"))
+ .withProperty("set", Collections.singleton("set"))
+ .build(), Optional.empty());
+
+ final Optional<ChampObject> retrievedReplacedBookooObject = graph.retrieveObject(replacedBookoo.getKey().get(), Optional.empty());
+
+ assertTrue(replacedBookoo.getProperties().size() == 3);
+ assertTrue(replacedBookoo.getProperty("property1").get().equals("value2"));
+ assertTrue(replacedBookoo.getProperty("list").get().equals(Collections.singletonList("list")));
+ assertTrue(replacedBookoo.getProperty("set").get().equals(Collections.singleton("set")));
+
+
+ if (!retrievedReplacedBookooObject.isPresent()) {
+ throw new AssertionError("Failed to retrieve stored object " + replacedBookoo);
+ }
+ if (!replacedBookoo.equals(retrievedReplacedBookooObject.get())) {
+ throw new AssertionError("Retrieved object does not equal stored object");
+ }
+
+ graph.deleteObject(storedBookooObject.getKey().get(), Optional.empty());
+
+ if (graph.retrieveObject(storedBookooObject.getKey().get(), Optional.empty()).isPresent()) {
+ throw new AssertionError("Object not successfully deleted");
+ }
+
+ assertTrue(graph.queryObjects(Collections.emptyMap(), Optional.empty()).count() == 0);
+ assertTrue(graph.queryRelationships(Collections.emptyMap(), Optional.empty()).count() == 0);
+
+
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError("Schema mismatch while storing object", e);
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError("Marshalling exception while storing object", e);
+ } catch (ChampUnmarshallingException e) {
+ throw new AssertionError("Unmarshalling exception while retrieving object", e);
+ } catch (ChampObjectNotExistsException e) {
+ throw new AssertionError("Missing object on delete/update", e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError("Transaction exception occurred", e);
+ }
+
+ try {
+ graph.deleteObject(storedBookooObject.getKey().get(), Optional.empty());
+ throw new AssertionError("Delete succeeded when it should have failed");
+ } catch (ChampObjectNotExistsException e) {
+ //Expected
+ } catch (ChampTransactionException e) {
+ throw new AssertionError("Transaction exception occurred", e);
+ }
+
+ try {
+ graph.storeObject(ChampObject.create()
+ .ofType("foo")
+ .withKey("non-existent object key")
+ .build(), Optional.empty());
+ throw new AssertionError("Expected ChampObjectNotExistsException but object was successfully stored");
+ } catch (ChampObjectNotExistsException e) {
+ //Expected
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+
+ try {
+ // validate the replaceObject method when Object key is not passed
+ graph.replaceObject(
+ ChampObject.create().ofType("foo").withoutKey().withProperty("property1", "value2").build(), Optional.empty());
+ } catch (ChampObjectNotExistsException e) {
+ // Expected
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public void testChampObjectReservedProperties(ChampGraph graph) {
+
+ for (ChampObject.ReservedPropertyKeys key : ChampObject.ReservedPropertyKeys.values()) {
+ try {
+ ChampObject.create()
+ .ofType(ChampObject.ReservedTypes.ANY.toString())
+ .withoutKey()
+ .withProperty(key.toString(), "")
+ .build();
+ throw new AssertionError("Allowed reserved property key to be used during object creation");
+ } catch (IllegalArgumentException e) {
+ //Expected
+ }
+ }
+ }
+
+ @Test
+ public void testFluentObjectCreation() {
+ final Object value1 = new Object();
+ final String value2 = "value2";
+ final float value3 = 0.0f;
+
+ final ChampObject champObject1 = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("key1", value1)
+ .withProperty("key2", value2)
+ .withProperty("key3", value3)
+ .build();
+
+ assertTrue(champObject1.getKey().equals(Optional.empty()));
+ assertTrue(champObject1.getKey().isPresent() == false);
+ assertTrue(champObject1.getType().equals("foo"));
+ assertTrue(champObject1.getProperty("key1").get() instanceof Object);
+ assertTrue(champObject1.getProperty("key1").get().equals(value1));
+ assertTrue(champObject1.getProperty("key2").get() instanceof String);
+ assertTrue(champObject1.getProperty("key2").get().equals(value2));
+ assertTrue(champObject1.getProperty("key3").get() instanceof Float);
+ assertTrue(champObject1.getProperty("key3").get().equals(value3));
+
+ final ChampObject champObject2 = ChampObject.create()
+ .ofType("foo")
+ .withKey(1)
+ .withProperty("key1", value1)
+ .withProperty("key2", value2)
+ .withProperty("key3", value3)
+ .build();
+
+ assertTrue(champObject2.getType().equals("foo"));
+ assertTrue(champObject2.getKey().isPresent() == true);
+ assertTrue(champObject2.getKey().get() instanceof Integer);
+ assertTrue(champObject2.getKey().get().equals(1));
+ assertTrue(champObject2.getProperty("key1").get() instanceof Object);
+ assertTrue(champObject2.getProperty("key1").get().equals(value1));
+ assertTrue(champObject2.getProperty("key2").get() instanceof String);
+ assertTrue(champObject2.getProperty("key2").get().equals(value2));
+ assertTrue(champObject2.getProperty("key3").get() instanceof Float);
+ assertTrue(champObject2.getProperty("key3").get().equals(value3));
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPartitionTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPartitionTest.java
new file mode 100644
index 0000000..1aafebe
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPartitionTest.java
@@ -0,0 +1,226 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.exceptions.*;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.Assert.assertTrue;
+
+public class ChampPartitionTest extends org.onap.aai.champcore.core.BaseChampAPITest {
+
+ @Test
+ public void runInMemoryTests() {
+ runTests("IN_MEMORY");
+ }
+
+ public void runTests(String apiType) {
+ final ChampAPI api = ChampAPI.Factory.newInstance(apiType);
+ final String graphName = ChampPartitionTest.class.getSimpleName();
+
+ ChampPartitionTest.testChampPartitionCrud(api.getGraph(graphName));
+ api.shutdown();
+ }
+
+ @Test
+ public void testPartitionToString() throws Exception {
+ final ChampObject foo = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .build();
+ final ChampObject bar = ChampObject.create()
+ .ofType("bar")
+ .withoutKey()
+ .build();
+ final ChampRelationship baz = ChampRelationship.create()
+ .ofType("baz")
+ .withoutKey()
+ .withSource()
+ .from(foo)
+ .build()
+ .withTarget()
+ .from(bar)
+ .build()
+ .build();
+
+ final ChampPartition partition = ChampPartition.create()
+ .withObject(foo)
+ .withObject(bar)
+ .withRelationship(baz)
+ .build();
+
+ assertTrue(partition.toString().equals("{objects: [{key: , type: bar, properties: {}},{key: , type: foo, properties: {}}], relationships: [{key: , type: baz, source: {key: , type: foo, properties: {}}, target: {key: , type: bar, properties: {}}, properties: {}}]}"));
+ //"{objects: [{key: \"\", type: \"foo\", properties: {}}], relationships: []}"
+ //"{objects: [{key: , type: foo, properties: {}}], relationships: []}"
+ //throw new Exception(partition.toString());
+ }
+
+ @Test
+ public void testHashCode() {
+
+ final ChampObject foo = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .build();
+ final ChampObject bar = ChampObject.create()
+ .ofType("bar")
+ .withoutKey()
+ .build();
+ final ChampRelationship baz = ChampRelationship.create()
+ .ofType("baz")
+ .withoutKey()
+ .withSource()
+ .from(foo)
+ .build()
+ .withTarget()
+ .from(bar)
+ .build()
+ .build();
+
+ final ChampPartition partition = ChampPartition.create()
+ .withObject(foo)
+ .withObject(bar)
+ .withRelationship(baz)
+ .build();
+
+ assertTrue(partition.getChampObjects().contains(foo));
+ assertTrue(partition.getChampObjects().contains(bar));
+ assertTrue(partition.getChampRelationships().contains(baz));
+ }
+
+ @Test
+ public void testBuilder() {
+ final ChampObject foo = new ChampObject.Builder("foo").build();
+ final ChampObject bar = new ChampObject.Builder("bar").build();
+ final ChampRelationship uses = new ChampRelationship.Builder(foo, bar, "uses")
+ .build();
+ final ChampPartition a = new ChampPartition.Builder()
+ .object(foo)
+ .objects(Collections.singleton(bar))
+ .relationship(uses)
+ .relationships(Collections.singleton(uses))
+ .build();
+ assertTrue(a.getChampObjects().size() == 2);
+ assertTrue(a.getChampObjects().contains(foo));
+ assertTrue(a.getChampObjects().contains(bar));
+
+ assertTrue(a.getChampRelationships().size() == 1);
+ assertTrue(a.getChampRelationships().contains(uses));
+ }
+
+ public static void testChampPartitionCrud(ChampGraph graph) {
+
+ final ChampObject foo = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("prop1", "value1")
+ .build();
+ final ChampObject bar = ChampObject.create()
+ .ofType("bar")
+ .withoutKey()
+ .withProperty("prop2", "value2")
+ .build();
+
+ final ChampRelationship baz = ChampRelationship.create()
+ .ofType("baz")
+ .withoutKey()
+ .withSource()
+ .from(foo)
+ .build()
+ .withTarget()
+ .from(bar)
+ .build()
+ .withProperty("prop3", "value3")
+ .build();
+
+ final ChampPartition partition = ChampPartition.create()
+ .withObject(foo)
+ .withObject(bar)
+ .withRelationship(baz)
+ .build();
+
+ assertTrue(partition.getIncidentRelationships(foo).contains(baz));
+ assertTrue(partition.getIncidentRelationships(bar).contains(baz));
+ assertTrue(partition.getIncidentRelationshipsByType(foo).get("baz").contains(baz));
+
+ try {
+ final ChampPartition storedPartition = graph.storePartition(partition);
+
+ ChampPartitionTest.retrievePartitionElements(graph, storedPartition, true);
+
+ graph.deletePartition(storedPartition);
+
+ ChampPartitionTest.retrievePartitionElements(graph, storedPartition, false);
+
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampObjectNotExistsException e) {
+ throw new AssertionError(e);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ } catch (ChampRelationshipNotExistsException e) {
+ throw new AssertionError(e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private static void retrievePartitionElements(ChampGraph graph, ChampPartition partition, boolean expectFound) {
+ for (ChampObject object : partition.getChampObjects()) {
+ try {
+ final Optional<ChampObject> retrievedObject = graph.retrieveObject(object.getKey().get());
+
+ if (!expectFound && retrievedObject.isPresent()) {
+ throw new AssertionError("Expected object to not be found, but it was found");
+ }
+ if (expectFound && !retrievedObject.isPresent()) {
+ throw new AssertionError("Expected object to be found, but it was not found");
+ }
+ } catch (ChampUnmarshallingException | ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ for (ChampRelationship relationship : partition.getChampRelationships()) {
+ try {
+ final Optional<ChampRelationship> retrievedRelationship = graph.retrieveRelationship(relationship.getKey().get());
+
+ if (!expectFound && retrievedRelationship.isPresent()) {
+ throw new AssertionError("Expected relationship to not be found, but it was found");
+ }
+ if (expectFound && !retrievedRelationship.isPresent()) {
+ throw new AssertionError("Expected relationship to be found, but it was not found");
+ }
+ } catch (ChampUnmarshallingException | ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPropertyConstraintTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPropertyConstraintTest.java
new file mode 100644
index 0000000..c82e055
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPropertyConstraintTest.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.aai.champcore.model.ChampCardinality;
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampPropertyConstraint;
+
+public class ChampPropertyConstraintTest {
+
+ @Test
+ public void testChampPropertyConstraint() {
+ final ChampField z = new ChampField.Builder("z").build();
+ final ChampField y = new ChampField.Builder("y").build();
+
+ final ChampPropertyConstraint a = new ChampPropertyConstraint.Builder(z)
+ .cardinality(ChampCardinality.SINGLE)
+ .required(false)
+ .build();
+ final ChampPropertyConstraint aEquivalent = new ChampPropertyConstraint.Builder(z)
+ .build();
+
+ final ChampPropertyConstraint b = new ChampPropertyConstraint.Builder(y)
+ .build();
+ assertTrue(a.equals(aEquivalent));
+ assertTrue(!a.equals(b));
+ assertTrue(!a.equals(new Object()));
+
+ assertTrue(a.toString().equals(aEquivalent.toString()));
+ assertTrue(!a.toString().equals(b.toString()));
+
+ assertTrue(a.compareTo(aEquivalent) == 0);
+ assertTrue(a.compareTo(b) != 0);
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipIndexTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipIndexTest.java
new file mode 100644
index 0000000..5b8c715
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipIndexTest.java
@@ -0,0 +1,179 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.exceptions.*;
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertTrue;
+
+public class ChampRelationshipIndexTest extends BaseChampAPITest {
+
+ @Test
+ public void runInMemoryTest() {
+ runTest("IN_MEMORY");
+ }
+
+ public void runTest(String apiType) {
+ final String graphName = ChampRelationshipIndexTest.class.getSimpleName();
+
+ final ChampAPI api = ChampAPI.Factory.newInstance(apiType);
+ testChampRelationshipIndexCrud(api.getGraph(graphName));
+ api.shutdown();
+ }
+
+ public void testChampRelationshipIndexCrud(ChampGraph graph) {
+
+ final ChampField relationshipField = new ChampField.Builder("propertyName").build();
+ final ChampRelationshipIndex relationshipIndex = new ChampRelationshipIndex.Builder("fooEdgeIndex", "foo", relationshipField).build();
+
+ //Test on an empty graph
+ testChampRelationshipIndexStorage(graph, relationshipIndex);
+ testChampRelationshipIndexDelete(graph, relationshipIndex);
+
+ //Test with existing data in graph
+ try {
+ graph.storeRelationship(ChampRelationship.create()
+ .ofType("uses")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("bar")
+ .withoutKey()
+ .build()
+ .build()
+ , Optional.empty());
+ testChampRelationshipIndexStorage(graph, relationshipIndex);
+ testChampRelationshipIndexDelete(graph, relationshipIndex);
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ } catch (ChampObjectNotExistsException e) {
+ throw new AssertionError(e);
+ } catch (ChampRelationshipNotExistsException e) {
+ throw new AssertionError(e);
+ } catch (ChampUnmarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private void testChampRelationshipIndexDelete(ChampGraph graph, ChampRelationshipIndex relationshipIndex) {
+
+ if (!graph.capabilities().canDeleteRelationshipIndices()) {
+ try {
+ graph.deleteRelationshipIndex("someindex");
+ throw new AssertionError("Graph claims it doesn't support relationship index delete, but it failed to throw UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ //Expected
+ } catch (ChampIndexNotExistsException e) {
+ throw new AssertionError("Graph claims it doesn't support relationship index delete, but it failed to throw UnsupportedOperationException");
+ }
+ } else {
+ try {
+ graph.deleteRelationshipIndex(relationshipIndex.getName());
+
+ final Optional<ChampRelationshipIndex> retrieveRelationshipIndex = graph.retrieveRelationshipIndex(relationshipIndex.getName());
+
+ if (retrieveRelationshipIndex.isPresent()) {
+ throw new AssertionError("Retrieve relationship index after deleting it");
+ }
+
+ final Stream<ChampRelationshipIndex> relationshipIndices = graph.retrieveRelationshipIndices();
+ final Collection<ChampRelationshipIndex> allRelationshipIndices = relationshipIndices.collect(Collectors.toList());
+
+ if (allRelationshipIndices.contains(relationshipIndex)) {
+ throw new AssertionError("Retrieve all relationship indices contains previously deleted index");
+ }
+ if (allRelationshipIndices.size() != 0) {
+ throw new AssertionError("Wrong number of relationship indices returned by retrieve all indices");
+ }
+ } catch (ChampIndexNotExistsException e) {
+ throw new AssertionError(e);
+ }
+
+ try {
+ graph.deleteRelationshipIndex(relationshipIndex.getName());
+ throw new AssertionError("Failed to throw exception on non-existent object index");
+ } catch (ChampIndexNotExistsException e) {
+ //Expected
+ }
+ }
+ }
+
+ private void testChampRelationshipIndexStorage(ChampGraph graph, ChampRelationshipIndex relationshipIndex) {
+
+ graph.storeRelationshipIndex(relationshipIndex);
+ graph.storeRelationshipIndex(relationshipIndex); //Test storing duplicate relationship index
+
+ assertTrue(!graph.retrieveObjectIndex(relationshipIndex.getName()).isPresent()); //Make sure this wasn't stored as an object index
+
+ final Optional<ChampRelationshipIndex> retrieveRelationshipIndex = graph.retrieveRelationshipIndex(relationshipIndex.getName());
+
+ if (!retrieveRelationshipIndex.isPresent()) {
+ throw new AssertionError("Failed to retrieve relationship index after storing it");
+ }
+ if (!relationshipIndex.equals(retrieveRelationshipIndex.get())) {
+ throw new AssertionError("Non-equal relationship index returned from API after storing it");
+ }
+
+ final Stream<ChampRelationshipIndex> relationshipIndices = graph.retrieveRelationshipIndices();
+ final Collection<ChampRelationshipIndex> allRelationshipIndices = relationshipIndices.collect(Collectors.toList());
+
+ if (!allRelationshipIndices.contains(relationshipIndex)) {
+ throw new AssertionError("Retrieve all relationship indices did not return previously stored relationship index");
+ }
+ if (allRelationshipIndices.size() != 1) {
+ throw new AssertionError("Wrong number of relationship indices returned by retrieve all indices");
+ }
+
+ assertTrue(!graph.retrieveRelationshipIndex("nonExistentIndexName").isPresent());
+ }
+
+ @Test
+ public void testFluentRelationshipIndexCreation() {
+ final ChampRelationshipIndex relationshipIndex = ChampRelationshipIndex.create()
+ .ofName("fooNameIndex")
+ .onType("foo")
+ .forField("name")
+ .build();
+
+ assertTrue(relationshipIndex.getName().equals("fooNameIndex"));
+ assertTrue(relationshipIndex.getType().equals("foo"));
+ assertTrue(relationshipIndex.getField().getName().equals("name"));
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipTest.java
new file mode 100644
index 0000000..3f17466
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampRelationshipTest.java
@@ -0,0 +1,310 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.exceptions.*;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationship.ReservedPropertyKeys;
+import org.onap.aai.champcore.model.ChampRelationship.ReservedTypes;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertTrue;
+
+public class ChampRelationshipTest extends BaseChampAPITest {
+
+ @Test
+ public void runInMemoryTest() {
+ runTest("IN_MEMORY");
+ }
+
+ public void runTest(String apiType) {
+ final String graphName = ChampRelationshipTest.class.getSimpleName();
+
+ final ChampAPI api = ChampAPI.Factory.newInstance(apiType);
+ ChampRelationshipTest.testChampRelationshipCrud(api.getGraph(graphName));
+ api.shutdown();
+ }
+
+ public static void testChampRelationshipCrud(ChampGraph graph) {
+ final ChampObject source = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("property1", "value1")
+ .build();
+
+ final ChampObject target = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .build();
+
+ try {
+ ChampTransaction tx = ChampRelationshipTest.getTransaction();
+
+ final ChampObject storedSource = graph.storeObject(source, Optional.of(tx));
+ final ChampObject storedTarget = graph.storeObject(target, Optional.of(tx));
+
+ final ChampRelationship relationship = new ChampRelationship.Builder(storedSource, storedTarget, "relationship")
+ .property("property-1", "value-1")
+ .property("property-2", 3)
+ .build();
+
+ final ChampRelationship storedRelationship = graph.storeRelationship(relationship, Optional.of(tx));
+ final Optional<ChampRelationship> retrievedRelationship = graph.retrieveRelationship(storedRelationship.getKey().get(), Optional.of(tx));
+
+ if (!retrievedRelationship.isPresent()) {
+ throw new AssertionError("Failed to retrieve stored relationship " + storedRelationship);
+ }
+ if (!storedRelationship.equals(retrievedRelationship.get())) {
+ throw new AssertionError("Retrieved relationship does not equal stored object");
+ }
+
+ assertTrue(retrievedRelationship.get().getProperty("property-1").get().equals("value-1"));
+ assertTrue(retrievedRelationship.get().getProperty("property-2").get().equals(3));
+
+ if (!graph.retrieveRelationships(storedRelationship.getSource(), Optional.of(tx)).collect(Collectors.toList()).contains(storedRelationship)) {
+ throw new AssertionError("Failed to retrieve relationships for source object");
+ }
+
+ final ChampRelationship updatedRelationship = ChampRelationship.create()
+ .from(retrievedRelationship.get())
+ .withKey(retrievedRelationship.get().getKey().get())
+ .withProperty("property-2", 4)
+ .build();
+
+ final ChampRelationship storedUpdRel = graph.storeRelationship(updatedRelationship, Optional.of(tx));
+ final Optional<ChampRelationship> retrievedUpdRel = graph.retrieveRelationship(storedUpdRel.getKey().get(), Optional.of(tx));
+
+ assertTrue(retrievedUpdRel.isPresent());
+ assertTrue(retrievedUpdRel.get().equals(storedUpdRel));
+ assertTrue(retrievedUpdRel.get().getProperty("property-1").get().equals("value-1"));
+ assertTrue(retrievedUpdRel.get().getProperty("property-2").get().equals(4));
+
+
+ // validate the replaceRelationship method
+ final ChampRelationship replacedRelationship = new ChampRelationship.Builder(storedSource, storedTarget, "relationship")
+ .key(retrievedRelationship.get().getKey().get())
+ .property("property-2", 4)
+ .build();
+
+ final ChampRelationship replacedRel = graph.replaceRelationship(replacedRelationship, Optional.of(tx));
+ final Optional<ChampRelationship> retrievedReplacedRel = graph
+ .retrieveRelationship(replacedRel.getKey().get(), Optional.of(tx));
+
+ assertTrue(replacedRel.getProperties().size() == 1);
+ assertTrue(replacedRel.getProperty("property-2").get().equals(4));
+
+ assertTrue(retrievedReplacedRel.get().getProperties().size() == 1);
+ assertTrue(retrievedReplacedRel.get().getProperty("property-2").get().equals(4));
+
+ if (!retrievedReplacedRel.isPresent()) {
+ throw new AssertionError("Failed to retrieve stored relationship " + replacedRel);
+ }
+ if (!replacedRel.equals(retrievedReplacedRel.get())) {
+ throw new AssertionError("Retrieved relationship does not equal stored object");
+ }
+
+
+ graph.deleteRelationship(retrievedRelationship.get(), Optional.of(tx));
+
+ if (graph.retrieveRelationship(relationship.getKey(), Optional.of(tx)).isPresent()) {
+ throw new AssertionError("Relationship not successfully deleted");
+ }
+
+ try {
+ graph.deleteRelationship(retrievedRelationship.get(), Optional.of(tx));
+ throw new AssertionError("Failed to throw exception for missing relationship");
+ } catch (ChampRelationshipNotExistsException e) {
+ //Expected
+ }
+
+ Map<String, Object> queryParams = new HashMap<>();
+ queryParams.put(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString(), "blah");
+ graph.queryRelationships(queryParams);
+
+ queryParams = new HashMap<>();
+ queryParams.put(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString(), "blah");
+ graph.queryRelationships(queryParams);
+
+ assertTrue(graph.queryRelationships(Collections.emptyMap(), Optional.of(tx)).count() == 0);
+ assertTrue(graph.queryObjects(Collections.emptyMap(), Optional.of(tx)).count() == 2);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError("Schema mismatch while storing object", e);
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError("Marshalling exception while storing object", e);
+ } catch (ChampUnmarshallingException e) {
+ throw new AssertionError("Unmarshalling exception while retrieving relationship", e);
+ } catch (ChampRelationshipNotExistsException e) {
+ throw new AssertionError("Attempted to delete non-existent relationship", e);
+ } catch (ChampObjectNotExistsException e) {
+ throw new AssertionError("Object does not exist after storing it", e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError("Transaction failure", e);
+ }
+
+ ChampTransaction tx = ChampRelationshipTest.getTransaction();
+ try {
+ graph.retrieveRelationships(ChampObject.create().ofType("").withoutKey().build(), Optional.of(tx));
+ throw new AssertionError("Failed to handle missing object while retrieving relationships");
+ } catch (ChampUnmarshallingException | ChampTransactionException e) {
+ throw new AssertionError(e);
+ } catch (ChampObjectNotExistsException e) {
+ //Expected
+ }
+ //Negative test cases for replace relationship
+
+ try {
+ graph.replaceRelationship(new ChampRelationship.Builder(ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .build(), ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .build(), "relationship")
+ .key("1234")
+ .property("property-2", 4)
+ .build(),
+ Optional.of(tx));
+ } catch (ChampUnmarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ } catch (ChampRelationshipNotExistsException e) {
+ throw new AssertionError(e);
+ } catch (IllegalArgumentException e) {
+ //expected
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+
+ try {
+ graph.replaceRelationship(new ChampRelationship.Builder(ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .build(), ChampObject.create()
+ .ofType("foo")
+ .withKey("456")
+ .build(), "relationship")
+ .property("property-2", 4)
+ .build(),
+ Optional.of(tx));
+ } catch (ChampUnmarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ } catch (ChampRelationshipNotExistsException e) {
+ //expected
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError(e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+
+
+ }
+
+ @Test
+ public void testFluentRelationshipCreation() {
+ final Object value1 = new Object();
+ final String value2 = "value2";
+ final float value3 = 0.0f;
+
+ final ChampRelationship champRelationship = ChampRelationship.create()
+ .ofType("foo")
+ .withoutKey()
+ .withSource()
+ .ofType("bar")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("baz")
+ .withKey(1)
+ .build()
+ .withProperty("key1", value1)
+ .withProperty("key2", value2)
+ .withProperty("key3", value3)
+ .build();
+
+ ChampTransaction tx = ChampRelationshipTest.getTransaction();
+ assertTrue(champRelationship.getKey().equals(Optional.empty()));
+ assertTrue(champRelationship.getType().equals("foo"));
+ assertTrue(champRelationship.getProperty("key1").get() instanceof Object);
+ assertTrue(champRelationship.getProperty("key1").get().equals(value1));
+ assertTrue(champRelationship.getProperty("key2").get() instanceof String);
+ assertTrue(champRelationship.getProperty("key2").get().equals(value2));
+ assertTrue(champRelationship.getProperty("key3").get() instanceof Float);
+ assertTrue(champRelationship.getProperty("key3").get().equals(value3));
+ }
+
+ @Test
+ public void testChampRelationshipEnums() {
+ for (ReservedPropertyKeys key : ChampRelationship.ReservedPropertyKeys.values()) {
+ assertTrue(ChampRelationship.ReservedPropertyKeys.valueOf(key.name()) == key);
+ }
+
+ for (ReservedTypes type : ChampRelationship.ReservedTypes.values()) {
+ assertTrue(ChampRelationship.ReservedTypes.valueOf(type.name()) == type);
+ }
+ }
+
+ public static ChampTransaction getTransaction() {
+ return new TestTransaction();
+ }
+
+ public static class TestTransaction extends ChampTransaction {
+
+ public TestTransaction() {
+
+ }
+ @Override
+ public void commit() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void rollback() {
+ // TODO Auto-generated method stub
+
+ }
+ @Override
+ public String id() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampSchemaTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampSchemaTest.java
new file mode 100644
index 0000000..ba62628
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampSchemaTest.java
@@ -0,0 +1,759 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.Set;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.model.ChampConnectionConstraint;
+import org.onap.aai.champcore.model.ChampConnectionMultiplicity;
+import org.onap.aai.champcore.model.ChampField;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObject.ReservedTypes;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampPropertyConstraint;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampSchema;
+import org.onap.aai.champcore.schema.AlwaysValidChampSchemaEnforcer;
+import org.onap.aai.champcore.schema.ChampSchemaEnforcer;
+import org.onap.aai.champcore.schema.DefaultChampSchemaEnforcer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class ChampSchemaTest extends BaseChampAPITest {
+
+ @Test
+ public void runInMemoryTest() {
+ runTest("IN_MEMORY");
+ }
+
+ public void runTest(String apiType) {
+ final String graphName = ChampSchemaTest.class.getSimpleName();
+
+ final ChampAPI api = ChampAPI.Factory.newInstance(apiType);
+
+ try {
+ ChampSchemaTest.testChampSchemaCrud(api.getGraph(graphName));
+ } catch (Throwable t) {
+ throw new AssertionError(apiType + " unit test failed", t);
+ }
+
+ api.shutdown();
+ }
+
+ public static void testChampSchemaCrud(ChampGraph graph) {
+
+ final ChampSchema schema = ChampSchema.create()
+ .withObjectConstraint()
+ .onType("foo")
+ .withPropertyConstraint()
+ .onField("property1")
+ .required()
+ .build()
+ .withPropertyConstraint()
+ .onField("property2")
+ .optional()
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("bar")
+ .withPropertyConstraint()
+ .onField("at")
+ .ofType(ChampField.Type.STRING)
+ .optional()
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("foo")
+ .targetedToAny()
+ .build()
+ .build()
+ .build();
+
+ try {
+ graph.storeSchema(schema);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ }
+
+ final ChampObject emptyFoo = ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .build();
+
+ try {
+ graph.storeObject(emptyFoo, Optional.empty());
+ } catch (ChampMarshallingException e1) {
+ throw new AssertionError(e1);
+ } catch (ChampSchemaViolationException e1) {
+ //Expected, since it does not have the required property "property1"
+ } catch (ChampObjectNotExistsException e) {
+ throw new AssertionError(e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+
+ final ChampSchema retrievedSchema = graph.retrieveSchema();
+
+ if (!schema.equals(retrievedSchema)) throw new AssertionError("Retrieved schema is not the same as the schema that was previously stored");
+
+ try {
+ graph.updateSchema(new ChampRelationshipConstraint.Builder("bard").build());
+ assertTrue(graph.retrieveSchema().getRelationshipConstraint("bard").isPresent());
+
+ graph.updateSchema(new ChampObjectConstraint.Builder("baz").build());
+ assertTrue(graph.retrieveSchema().getObjectConstraint("baz").isPresent());
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ }
+
+ final ChampSchema updatedSchema = graph.retrieveSchema();
+
+ if (!updatedSchema.getObjectConstraint("baz").isPresent()) throw new AssertionError("Updated schema and retrieved, but retrieved schema did not contain updates");
+ if (!updatedSchema.getRelationshipConstraint("bard").isPresent()) throw new AssertionError("Updated schema and retrieved, but retrieved schema did not contain updates");
+
+ try {
+ graph.updateSchema(new ChampObjectConstraint.Builder("foo")
+ .constraint(
+ new ChampPropertyConstraint.Builder(
+ new ChampField.Builder("property2")
+ .build()
+ )
+ .required(false)
+ .build()
+ )
+ .build());
+
+ final ChampObject storedEmptyFoo = graph.storeObject(emptyFoo, Optional.empty());
+
+ graph.deleteObject(storedEmptyFoo.getKey().get(), Optional.empty());
+ } catch (ChampMarshallingException e) {
+ throw new AssertionError(e);
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ } catch (ChampObjectNotExistsException e) {
+ throw new AssertionError(e);
+ } catch (ChampTransactionException e) {
+ throw new AssertionError(e);
+ }
+
+ graph.deleteSchema();
+ assertTrue(graph.retrieveSchema().equals(ChampSchema.emptySchema()));
+ }
+
+ @Test
+ public void testChampSchemaFluentApi() {
+ final ChampSchema schema = ChampSchema.create()
+ .withObjectConstraint()
+ .onType("foo")
+ .withPropertyConstraint()
+ .onField("bar")
+ .ofType(ChampField.Type.STRING)
+ .required()
+ .build()
+ .withPropertyConstraint()
+ .onField("baz")
+ .ofType(ChampField.Type.BOOLEAN)
+ .optional()
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("eats")
+ .withPropertyConstraint()
+ .onField("at")
+ .ofType(ChampField.Type.STRING)
+ .required()
+ .build()
+ .withPropertyConstraint()
+ .onField("for")
+ .optional()
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("foo")
+ .targetedTo("foo")
+ .withMultiplicity(ChampConnectionMultiplicity.ONE)
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("bar")
+ .targetedTo("bar")
+ .build()
+ .build()
+ .build();
+
+ assertTrue(schema.getObjectConstraint("foo").get().getType().equals("foo"));
+
+ for (ChampPropertyConstraint propConst : schema.getObjectConstraint("foo").get().getPropertyConstraints()) {
+ if (propConst.getField().getName().equals("bar")) {
+ assertTrue(propConst.getField().getJavaType().equals(String.class));
+ assertTrue(propConst.isRequired());
+ } else if (propConst.getField().getName().equals("baz")) {
+ assertTrue(propConst.getField().getJavaType().equals(Boolean.class));
+ assertTrue(!propConst.isRequired());
+ } else {
+ throw new AssertionError("Unknown property constraint found: " + propConst);
+ }
+ }
+
+ assertTrue(schema.getRelationshipConstraint("eats").get().getType().equals("eats"));
+
+ for (ChampPropertyConstraint propConst : schema.getRelationshipConstraint("eats").get().getPropertyConstraints()) {
+ if (propConst.getField().getName().equals("at")) {
+ assertTrue(propConst.getField().getJavaType().equals(String.class));
+ assertTrue(propConst.isRequired());
+ } else if (propConst.getField().getName().equals("for")) {
+ assertTrue(propConst.getField().getJavaType().equals(String.class));
+ assertTrue(!propConst.isRequired());
+ } else {
+ throw new AssertionError("Unknown property constraint found: " + propConst);
+ }
+ }
+
+ for (ChampConnectionConstraint connConst : schema.getRelationshipConstraint("eats").get().getConnectionConstraints()) {
+ if (connConst.getSourceType().equals("foo")) {
+ assertTrue(connConst.getTargetType().equals("foo"));
+ assertTrue(connConst.getMultiplicity() == ChampConnectionMultiplicity.ONE);
+ } else if (connConst.getSourceType().equals("bar")) {
+ assertTrue(connConst.getTargetType().equals("bar"));
+ assertTrue(connConst.getMultiplicity() == ChampConnectionMultiplicity.MANY);
+ } else {
+ throw new AssertionError("Unknown connection constraint found: " + connConst);
+ }
+ }
+ }
+
+ @Test
+ public void testDefaultChampSchemaEnforcer() {
+
+ final ChampSchemaEnforcer schemaEnforcer = new DefaultChampSchemaEnforcer();
+ final ChampSchema champSchema = ChampSchema.create()
+ .withObjectConstraint()
+ .onType("foo")
+ .withPropertyConstraint()
+ .onField("bar")
+ .ofType(ChampField.Type.STRING)
+ .required()
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("makes")
+ .withPropertyConstraint()
+ .onField("bar")
+ .required()
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("foo")
+ .targetedTo("fiz")
+ .withMultiplicity(ChampConnectionMultiplicity.ONE)
+ .build()
+ .build()
+ .build();
+
+ try {
+ schemaEnforcer.validate(ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", "true")
+ .build(),
+ champSchema.getObjectConstraint("foo").get());
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ }
+
+ try {
+ schemaEnforcer.validate(ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .build(),
+ champSchema.getObjectConstraint("foo").get());
+ throw new AssertionError("Failed to enforce required property constraint on object");
+ } catch (ChampSchemaViolationException e) {
+ //Expected
+ }
+
+ try {
+ schemaEnforcer.validate(ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", true)
+ .build(),
+ champSchema.getObjectConstraint("foo").get());
+ throw new AssertionError("Failed to enforce property type constraint on object");
+ } catch (ChampSchemaViolationException e) {
+ //Expected
+ }
+
+ try {
+ schemaEnforcer.validate(ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .withProperty("bar", "true")
+ .build(),
+ champSchema.getRelationshipConstraint("makes").get()
+ );
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ }
+
+ try {
+ schemaEnforcer.validate(ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .build(),
+ champSchema.getRelationshipConstraint("makes").get()
+ );
+ throw new AssertionError("Failed to enforce required property constraint on relationship");
+ } catch (ChampSchemaViolationException e) {
+ //Expected
+ }
+
+ try {
+ schemaEnforcer.validate(ChampPartition.create()
+ .withObject(
+ ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", "true")
+ .build()
+ )
+ .withObject(
+ ChampObject.create()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ )
+ .withRelationship(
+ ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", "true")
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .withProperty("bar", "true")
+ .build()
+ )
+ .withRelationship(
+ ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", "true")
+ .build()
+ .withProperty("bar", "true")
+ .build()
+ )
+ .build(),
+ champSchema
+ );
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ }
+
+ try {
+ schemaEnforcer.validate(ChampPartition.create()
+ .withObject(
+ ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", "true")
+ .build()
+ )
+ .withObject(
+ ChampObject.create()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ )
+ .withRelationship(
+ ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", "true")
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .withProperty("bar", "true")
+ .build()
+ )
+ .withRelationship(
+ ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", "true")
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .withProperty("bar", "true")
+ .build()
+ )
+ .build(),
+ champSchema
+ );
+ throw new AssertionError("Failed to enforce connection constraint on relationship type 'makes'");
+ } catch (ChampSchemaViolationException e) {
+ //Expected
+ }
+ }
+
+ @Test
+ public void testAlwaysValidChampSchemaEnforcer() {
+
+ final ChampSchemaEnforcer schemaEnforcer = new AlwaysValidChampSchemaEnforcer();
+
+ try {
+ schemaEnforcer.validate(ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", true)
+ .build(),
+ new ChampObjectConstraint.Builder("foo")
+ .constraint(
+ new ChampPropertyConstraint.Builder(
+ new ChampField.Builder("bar")
+ .type(ChampField.Type.STRING)
+ .build()
+ )
+ .required(true)
+ .build()
+ )
+ .build()
+ );
+
+ schemaEnforcer.validate(ChampRelationship.create()
+ .ofType("foo")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .withProperty("bar", true)
+ .build(),
+ new ChampRelationshipConstraint.Builder("bar")
+ .constraint(
+ new ChampPropertyConstraint.Builder(
+ new ChampField.Builder("bar")
+ .type(ChampField.Type.STRING)
+ .build()
+ )
+ .required(true)
+ .build()
+ )
+ .build()
+ );
+
+ schemaEnforcer.validate(ChampPartition.create()
+ .withObject(
+ ChampObject.create()
+ .ofType("foo")
+ .withoutKey()
+ .withProperty("bar", true)
+ .build()
+ )
+ .withObject(
+ ChampObject.create()
+ .ofType("fiz")
+ .withoutKey()
+ .withProperty("bar", true)
+ .build()
+ )
+ .withRelationship(
+ ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .build()
+ )
+ .withRelationship(
+ ChampRelationship.create()
+ .ofType("makes")
+ .withoutKey()
+ .withSource()
+ .ofType("foo")
+ .withoutKey()
+ .build()
+ .withTarget()
+ .ofType("fiz")
+ .withoutKey()
+ .build()
+ .withProperty("bar", true)
+ .build()
+ )
+ .build(),
+ ChampSchema.create()
+ .withObjectConstraint()
+ .onType("foo")
+ .withPropertyConstraint()
+ .onField("bar")
+ .required()
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("makes")
+ .withPropertyConstraint()
+ .onField("bar")
+ .required()
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("foo")
+ .targetedTo("fiz")
+ .withMultiplicity(ChampConnectionMultiplicity.ONE)
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("uses")
+ .withConnectionConstraint()
+ .sourcedFromAny()
+ .targetedTo("computer")
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("destroys")
+ .withConnectionConstraint()
+ .sourcedFrom("computer")
+ .targetedToAny()
+ .build()
+ .build()
+ .build()
+
+ );
+ } catch (ChampSchemaViolationException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Test
+ public void testFluentSchemaApi() {
+ final ChampSchema schema = ChampSchema.create()
+ .withObjectConstraint()
+ .onType("a")
+ .withPropertyConstraint()
+ .onField("z")
+ .ofType(ChampField.Type.STRING)
+ .optional()
+ .build()
+ .build()
+ .withObjectConstraint()
+ .onType("b")
+ .withPropertyConstraint()
+ .onField("y")
+ .ofType(ChampField.Type.LONG)
+ .required()
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("one")
+ .withPropertyConstraint()
+ .onField("nine")
+ .ofType(ChampField.Type.INTEGER)
+ .optional()
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("a")
+ .targetedTo("b")
+ .withMultiplicity(ChampConnectionMultiplicity.NONE)
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("a")
+ .targetedToAny()
+ .withMultiplicity(ChampConnectionMultiplicity.ONE)
+ .build()
+ .withConnectionConstraint()
+ .sourcedFromAny()
+ .targetedTo("b")
+ .withMultiplicity(ChampConnectionMultiplicity.MANY)
+ .build()
+ .withConnectionConstraint()
+ .sourcedFromAny()
+ .targetedToAny()
+ .withMultiplicity(ChampConnectionMultiplicity.MANY)
+ .build()
+ .build()
+ .build();
+
+ final ChampObjectConstraint aObjConstraint = schema.getObjectConstraint("a").get();
+
+ assertTrue(aObjConstraint.getType().equals("a"));
+
+ final ChampPropertyConstraint zPropertyConstraint = aObjConstraint.getPropertyConstraint("z").get();
+
+ assertTrue(zPropertyConstraint.getField().getName().equals("z"));
+ assertTrue(zPropertyConstraint.getField().getJavaType().equals(String.class));
+ assertTrue(!zPropertyConstraint.isRequired());
+
+ final ChampObjectConstraint bObjConstraint = schema.getObjectConstraint("b").get();
+
+ assertTrue(bObjConstraint.getType().equals("b"));
+
+ final ChampPropertyConstraint yPropertyConstraint = bObjConstraint.getPropertyConstraint("y").get();
+
+ assertTrue(yPropertyConstraint.getField().getName().equals("y"));
+ assertTrue(yPropertyConstraint.getField().getJavaType().equals(Long.class));
+ assertTrue(yPropertyConstraint.isRequired());
+
+ final ChampRelationshipConstraint oneRelConstraint = schema.getRelationshipConstraint("one").get();
+
+ assertTrue(oneRelConstraint.getType().equals("one"));
+
+ final ChampPropertyConstraint ninePropertyConstraint = oneRelConstraint.getPropertyConstraint("nine").get();
+
+ assertTrue(ninePropertyConstraint.getField().getName().equals("nine"));
+ assertTrue(ninePropertyConstraint.getField().getJavaType().equals(Integer.class));
+ assertTrue(!ninePropertyConstraint.isRequired());
+
+ final Set<ChampConnectionConstraint> connectionConstraints = oneRelConstraint.getConnectionConstraints();
+
+ for (ChampConnectionConstraint cc : connectionConstraints) {
+ if (cc.getSourceType().equals("a") && cc.getTargetType().equals("b")) {
+ assertTrue(cc.getMultiplicity() == ChampConnectionMultiplicity.NONE);
+ } else if (cc.getSourceType().equals(ReservedTypes.ANY.toString()) && cc.getTargetType().equals("b")) {
+ assertTrue(cc.getMultiplicity() == ChampConnectionMultiplicity.MANY);
+ } else if (cc.getSourceType().equals(ReservedTypes.ANY.toString()) && cc.getTargetType().equals(ReservedTypes.ANY.toString())) {
+ assertTrue(cc.getMultiplicity() == ChampConnectionMultiplicity.MANY);
+ } else if (cc.getSourceType().equals("a") && cc.getTargetType().equals(ReservedTypes.ANY.toString())) {
+ assertTrue(cc.getMultiplicity() == ChampConnectionMultiplicity.ONE);
+ } else {
+ throw new AssertionError("Found unspecified connection constraint " + cc);
+ }
+ }
+ }
+
+ @Test
+ public void testJacksonObjectMapping() {
+ final ChampSchema schema = ChampSchema.create()
+ .withObjectConstraint()
+ .onType("a")
+ .withPropertyConstraint()
+ .onField("z")
+ .ofType(ChampField.Type.STRING)
+ .optional()
+ .build()
+ .build()
+ .withObjectConstraint()
+ .onType("b")
+ .withPropertyConstraint()
+ .onField("y")
+ .ofType(ChampField.Type.LONG)
+ .required()
+ .build()
+ .build()
+ .withRelationshipConstraint()
+ .onType("one")
+ .withPropertyConstraint()
+ .onField("nine")
+ .ofType(ChampField.Type.INTEGER)
+ .optional()
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("a")
+ .targetedTo("b")
+ .withMultiplicity(ChampConnectionMultiplicity.NONE)
+ .build()
+ .withConnectionConstraint()
+ .sourcedFrom("a")
+ .targetedToAny()
+ .withMultiplicity(ChampConnectionMultiplicity.ONE)
+ .build()
+ .withConnectionConstraint()
+ .sourcedFromAny()
+ .targetedTo("b")
+ .withMultiplicity(ChampConnectionMultiplicity.MANY)
+ .build()
+ .withConnectionConstraint()
+ .sourcedFromAny()
+ .targetedToAny()
+ .withMultiplicity(ChampConnectionMultiplicity.MANY)
+ .build()
+ .build()
+ .build();
+
+ final ObjectMapper om = new ObjectMapper();
+
+ try {
+ final byte[] serialized = om.writeValueAsBytes(schema);
+ System.out.println(new String(serialized, "UTF-8"));
+ final ChampSchema deserialized = om.readValue(serialized, ChampSchema.class);
+ assert schema.equals(deserialized);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampTransactionTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampTransactionTest.java
new file mode 100644
index 0000000..30f033c
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampTransactionTest.java
@@ -0,0 +1,502 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.core;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.FeatureDescriptor;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampCapabilities;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.NoOpTinkerPopTransaction;
+import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.graph.impl.AbstractTinkerpopChampGraph;
+import org.onap.aai.champcore.graph.impl.TinkerpopTransaction;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+import org.onap.aai.champcore.schema.ChampSchemaEnforcer;
+
+
+public class ChampTransactionTest {
+
+ TestGraph g = null;
+
+ @Before
+ public void setup() {
+ g = new TestGraph();
+ }
+
+ /**
+ * This test validates the behaviour when the underlying graph implementation
+ * does not support transactions.
+ */
+ @Test
+ public void testNoTransactionSupport() {
+
+ // By default our test graph should be configured to support transactions, but
+ // set it explicitly anyway just to be sure.
+ g.setTransactionSupport(true);
+
+ // Now, try to start a new transaction against our graph - it should succeed.
+ TinkerpopTransaction t = new TinkerpopTransaction(g);
+ Graph gi = t.getGraphInstance(); // GDF: Making jacoco happy...
+
+ // Now, configure our graph to specify that transactions are NOT supported.
+ g.setTransactionSupport(false);
+
+ try {
+
+ // Now, try to start a new transaction against our graph.
+ t = new TinkerpopTransaction(g);
+
+ } catch (UnsupportedOperationException e) {
+
+ // If we're here, it's all good since we expected an exception to be thrown (since our
+ // graph does NOT support transactions).
+ return;
+ }
+
+ // If we're here then we were able to open a transaction even though our graph does
+ // not support that functionality.
+ fail("Attempt to open a transaction against a graph with no transaction support should not succeed.");
+ }
+
+
+ /**
+ * This test validates the behaviour when committing a transaction under various
+ * circumstances.
+ * @throws ChampTransactionException
+ */
+ @Test
+ public void testCommit() throws ChampTransactionException {
+
+ // By default our test graph should simulate successful commits, but set
+ // the configuration anyway, just to be sure.
+ g.setFailCommits(false);
+
+ // Now, start a transaction.
+ TinkerpopTransaction t = new TinkerpopTransaction(g);
+
+ // Call commit against the transaction - it should complete successfully.
+ t.commit();
+
+ // Now, configure our test graph to simulate failing to commit.
+ g.setFailCommits(true);
+
+ // Open another transaction...
+ t = new TinkerpopTransaction(g);
+ boolean exceptionThrown = false;
+ try {
+
+ //...and try to commit it.
+ t.commit();
+
+ } catch (Throwable e) {
+
+ // Our commit should have failed and ultimately thrown an exception - so if we
+ // are here then it's all good.
+ exceptionThrown = true;
+ }
+
+ assertTrue("Failed commit should have produced an exception.", exceptionThrown);
+ }
+
+
+ @Test
+ public void testRollback() throws ChampTransactionException {
+
+ // By default our test graph should simulate successful commits, but set
+ // the configuration anyway, just to be sure.
+ g.setFailCommits(false);
+
+ // Now, start a transaction.
+ TinkerpopTransaction t = new TinkerpopTransaction(g);
+
+ // Call rollback against the transaction - it should complete successfully.
+ t.rollback();
+
+ // Now, configure our test graph to simulate failing to commit.
+ g.setFailCommits(true);
+
+ // Open another transaction...
+ t = new TinkerpopTransaction(g);
+ boolean exceptionThrown = false;
+ try {
+
+ //...and try to commit it.
+ t.rollback();
+
+ } catch (Throwable e) {
+
+ // Our commit should have failed and ultimately thrown an exception - so if we
+ // are here then it's all good.
+ exceptionThrown = true;
+ }
+
+ assertTrue("Failed rollback should have produced an exception.", exceptionThrown);
+ }
+
+ @Test
+ public void test() throws ChampTransactionException {
+
+ AbstractTinkerpopChampGraph graph = new AbstractTinkerpopChampGraph(new HashMap<String, Object>()) {
+
+ @Override
+ protected Graph getGraph() {
+ return TinkerGraph.open();
+ }
+
+ @Override
+ protected ChampSchemaEnforcer getSchemaEnforcer() {
+ return null;
+ }
+
+ @Override
+ public void executeStoreObjectIndex(ChampObjectIndex index) { }
+
+ @Override
+ public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName) {
+ return null;
+ }
+
+ @Override
+ public Stream<ChampObjectIndex> retrieveObjectIndices() {
+ return null;
+ }
+
+ @Override
+ public void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException {}
+
+ @Override
+ public void executeStoreRelationshipIndex(ChampRelationshipIndex index) {}
+
+ @Override
+ public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName) {
+ return null;
+ }
+
+ @Override
+ public Stream<ChampRelationshipIndex> retrieveRelationshipIndices() {
+ return null;
+ }
+
+ @Override
+ public void executeDeleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException {}
+
+ @Override
+ public ChampCapabilities capabilities() {
+ return null;
+ }
+
+ @Override
+ public GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ };
+
+ TinkerpopTransaction t = new TinkerpopTransaction(g);
+ t.id();
+ graph.commitTransaction(t);
+ graph.rollbackTransaction(t);
+
+ }
+
+ private class TestGraph implements Graph {
+
+ private boolean supportsTransactions = true;
+ private boolean failCommits = false;
+
+
+ public void setTransactionSupport(boolean supportsTransactions) {
+ this.supportsTransactions = supportsTransactions;
+ }
+
+ public void setFailCommits(boolean failCommits) {
+ this.failCommits = failCommits;
+ }
+ @Override
+ public Vertex addVertex(Object... keyValues) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void close() throws Exception {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public GraphComputer compute() throws IllegalArgumentException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public <C extends GraphComputer> C compute(Class<C> graphComputerClass)
+ throws IllegalArgumentException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Configuration configuration() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Iterator<Edge> edges(Object... edgeIds) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Transaction tx() {
+ return new TestTransaction();
+ }
+
+ @Override
+ public Variables variables() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Iterator<Vertex> vertices(Object... vertexIds) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Gets the {@link Features} exposed by the underlying {@code Graph} implementation.
+ */
+ public Features features() {
+ return new TestFeatures() {
+ };
+ }
+
+ public class TestFeatures implements Graph.Features {
+
+ /**
+ * Gets the features related to "graph" operation.
+ */
+ public GraphFeatures graph() {
+ return new TestGraphFeatures() {
+ };
+ }
+
+ public class TestGraphFeatures implements Graph.Features.GraphFeatures {
+
+ /**
+ * Determines if the {@code Graph} implementations supports transactions.
+ */
+ @FeatureDescriptor(name = FEATURE_TRANSACTIONS)
+ public boolean supportsTransactions() {
+ return supportsTransactions;
+ }
+ }
+ }
+ }
+
+ private class TestTransaction implements Transaction {
+
+ @Override
+ public void addTransactionListener(Consumer<Status> listener) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void clearTransactionListeners() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void close() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void commit() {
+
+ if(g.failCommits) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public <G extends Graph> G createThreadedTx() {
+ return (G) g;
+ }
+
+ @Override
+ public boolean isOpen() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Transaction onClose(Consumer<Transaction> consumer) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Transaction onReadWrite(Consumer<Transaction> consumer) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void open() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void readWrite() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void removeTransactionListener(Consumer<Status> listener) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void rollback() {
+ if(g.failCommits) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public <R> Workload<R> submit(Function<Graph, R> work) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+
+ private class TestTinkerpopGraph extends AbstractTinkerpopChampGraph {
+
+ protected TestTinkerpopGraph(Map<String, Object> properties) {
+ super(properties);
+ }
+
+ @Override
+ protected Graph getGraph() {
+ return TinkerGraph.open();
+ }
+
+
+ @Override
+ protected ChampSchemaEnforcer getSchemaEnforcer() {
+ return null;
+ }
+
+ @Override
+ public void executeStoreObjectIndex(ChampObjectIndex index) {
+ }
+
+ @Override
+ public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Stream<ChampObjectIndex> retrieveObjectIndices() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void executeStoreRelationshipIndex(ChampRelationshipIndex index) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Stream<ChampRelationshipIndex> retrieveRelationshipIndices() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void executeDeleteRelationshipIndex(String indexName)
+ throws ChampIndexNotExistsException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public ChampCapabilities capabilities() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/event/AbstractLoggingChampGraphTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/event/AbstractLoggingChampGraphTest.java
new file mode 100644
index 0000000..1f7451a
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/event/AbstractLoggingChampGraphTest.java
@@ -0,0 +1,1181 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.event;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.champcore.ChampCapabilities;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampObjectConstraint;
+import org.onap.aai.champcore.model.ChampObjectIndex;
+import org.onap.aai.champcore.model.ChampPartition;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.ChampRelationshipConstraint;
+import org.onap.aai.champcore.model.ChampRelationshipIndex;
+import org.onap.aai.champcore.model.ChampSchema;
+
+import org.onap.aai.event.api.EventPublisher;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+
+public class AbstractLoggingChampGraphTest {
+
+ /** Event stream producer stub. */
+ private InMemoryPublisher producer;
+
+ /** In memory graph for testing purposes. */
+ private TestGraph testGraph;
+
+
+ /**
+ * Perform any setup tasks that need to be done prior to each test.
+ */
+ @Before
+ public void setup() {
+
+ // Instantiate an event stream producer stub to use in our tests.
+ producer = new InMemoryPublisher();
+
+ // Instantiate an 'in-memory' graph for test purposes.
+ Map<String, Object> graphProperties = new HashMap<String, Object>();
+ graphProperties.put("champcore.event.stream.hosts", "myeventstreamhost");
+ graphProperties.put("champcore.event.stream.batch-size", 1);
+ graphProperties.put("champcore.event.stream.publisher", producer);
+ testGraph = new TestGraph(graphProperties);
+ }
+
+
+ /**
+ * Perform any cleanup that needs to be done after each test.
+ *
+ * @throws Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+
+ // Close our stubbed producer and graph.
+ producer.close();
+ testGraph.shutdown();
+ }
+
+
+ /**
+ * Validates that store/replace/delete operation against vertices result in the expected events
+ * being published to the event stream.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampTransactionException
+ */
+ @Test
+ public void vertexOperationsEmptyTransactionsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampTransactionException {
+
+ // Create a vertex and store it in the graph data store.
+ ChampObject obj1 = ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .build();
+ testGraph.storeObject(obj1, Optional.empty());
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected STORE event.", loggedEventStr.contains("STORE"));
+ assertTrue("Entity type for store event was not a vertex.", loggedEventStr.contains("vertex"));
+
+
+
+ // Create a new vertex based on the one that we already created.
+ ChampObject obj2 = ChampObject.create()
+ .from(obj1)
+ .withKey("123")
+ .withProperty("p3", "v3")
+ .build();
+
+ // Now, try doing a replace operation.
+ testGraph.replaceObject(obj2, Optional.empty());
+
+
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected REPLACE event.", loggedEventStr.contains("REPLACE"));
+ assertTrue("Entity type for store event was not a vertex.", loggedEventStr.contains("vertex"));
+
+ // Finally, delete the vertex.
+ testGraph.deleteObject("123", Optional.empty());
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected DELETE event.", loggedEventStr.contains("DELETE"));
+ assertTrue("Entity type for store event was not a vertex.", loggedEventStr.contains("vertex"));
+ }
+
+ @Test
+ public void vertexOperationsLegacyTest2() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampTransactionException {
+
+ // Create a vertex and store it in the graph data store.
+ ChampObject obj1 = ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .build();
+ testGraph.storeObject(obj1);
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected STORE event.", loggedEventStr.contains("STORE"));
+ assertTrue("Entity type for store event was not a vertex.", loggedEventStr.contains("vertex"));
+
+
+
+ // Create a new vertex based on the one that we already created.
+ ChampObject obj2 = ChampObject.create()
+ .from(obj1)
+ .withKey("123")
+ .withProperty("p3", "v3")
+ .build();
+
+ // Now, try doing a replace operation.
+ testGraph.replaceObject(obj2);
+
+
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected REPLACE event.", loggedEventStr.contains("REPLACE"));
+ assertTrue("Entity type for store event was not a vertex.", loggedEventStr.contains("vertex"));
+
+ // Finally, delete the vertex.
+ testGraph.deleteObject("123");
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected DELETE event.", loggedEventStr.contains("DELETE"));
+ assertTrue("Entity type for store event was not a vertex.", loggedEventStr.contains("vertex"));
+ }
+
+ /**
+ * This test validates that performing vertex operations in the case where the data to be
+ * forwarded to the event stream is unavailable results in no event being generated, but
+ * does not otherwise create issues.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampTransactionException
+ */
+ @Test
+ public void vertexOperationsWithNullsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException, ChampTransactionException {
+
+ // Setup our test graph to simulate failures to retrieve data from the graph data store.
+ testGraph.returnNulls();
+
+ // Create a vertex and store it in the graph data store.
+ ChampObject obj1 = ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .build();
+ testGraph.storeObject(obj1, Optional.empty());
+
+ // Check our simulated event stream to verify that an event log was produced.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Store vertex event should not have been logged to the event stream", loggedEventStr);
+
+ // Create a new vertex based on the one that we already created.
+ ChampObject obj2 = ChampObject.create()
+ .from(obj1)
+ .withKey("123")
+ .withProperty("p3", "v3")
+ .build();
+
+ // Now, try doing a replace operation.
+ testGraph.replaceObject(obj2, Optional.empty());
+
+ // Check our simulated event stream to see if an event log was not produced.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Store vertex event should not have been logged to the event stream", loggedEventStr);
+
+ // Finally, delete the vertex.
+ testGraph.deleteObject("123", Optional.empty());
+
+ // Check our simulated event stream to see if an event log was not produced.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Store vertex event should not have been logged to the event stream", loggedEventStr);
+ }
+
+
+ /**
+ * Validates that store/replace/delete operation against edges result in the expected events
+ * being published to the event stream.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampTransactionException
+ */
+ @Test
+ public void edgeOperationsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+
+ // Create two vertices to act as the end points of our edge.
+ ChampObject obj1 = ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .build();
+
+ ChampObject obj2 = ChampObject.create()
+ .ofType("bar")
+ .withKey("123")
+ .withProperty("p3", "v3")
+ .build();
+
+ // Now, create an edge object and write it to the graph data store.
+ ChampRelationship rel = new ChampRelationship.Builder(obj1, obj2, "relationship")
+ .property("property-1", "value-1")
+ .property("property-2", "value-2")
+ .build();
+ testGraph.storeRelationship(rel, Optional.empty());
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected STORE event.", loggedEventStr.contains("STORE"));
+ assertTrue("Entity type for store event was not an edge.", loggedEventStr.contains("relationship"));
+
+ // Now, create another edge object based on the one we just wrote, and use it to perform
+ // a replace operation.
+ ChampRelationship rel2 = ChampRelationship.create()
+ .from(rel)
+ .withKey("123")
+ .withProperty("property-3", "value-3")
+ .build();
+ testGraph.replaceRelationship(rel2, Optional.empty());
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected REPLACE event.", loggedEventStr.contains("REPLACE"));
+ assertTrue("Entity type for store event was not an edge.", loggedEventStr.contains("relationship"));
+
+ // Finally, delete our edge.
+ testGraph.deleteRelationship(rel2, Optional.empty());
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected DELETE event.", loggedEventStr.contains("DELETE"));
+ assertTrue("Entity type for store event was not an edge.", loggedEventStr.contains("relationship"));
+ }
+
+
+ /**
+ * This test validates that performing edge operations in the case where the data to be
+ * forwarded to the event stream is unavailable results in no event being generated, but
+ * does not otherwise create issues.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampTransactionException
+ */
+ @Test
+ public void edgeOperationsWithNullsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+
+ // Set up our graph to simulate a failure to retrieve some of the data we need to generate
+ // events.
+ testGraph.returnNulls();
+
+ // Create two vertices to act as the endpoints of our edge.
+ ChampObject obj1 = ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .build();
+
+ ChampObject obj2 = ChampObject.create()
+ .ofType("bar")
+ .withKey("123")
+ .withProperty("p3", "v3")
+ .build();
+
+ // Now, create an edge object and write it to the graph data store.
+ ChampRelationship rel = new ChampRelationship.Builder(obj1, obj2, "relationship")
+ .property("property-1", "value-1")
+ .property("property-2", "value-2")
+ .build();
+ testGraph.storeRelationship(rel, Optional.empty());
+
+ // Check our simulated event stream to see if an event log was produced.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Store edge event should not have been logged to the event stream", loggedEventStr);
+
+ // Now, create another edge object based on the one we just wrote, and use it to perform
+ // a replace operation.
+ ChampRelationship rel2 = ChampRelationship.create()
+ .from(rel)
+ .withKey("123")
+ .withProperty("property-3", "value-3")
+ .build();
+ testGraph.replaceRelationship(rel2, Optional.empty());
+
+ // Check our simulated event stream to see if an event log was produced.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Store edge event should not have been logged to the event stream", loggedEventStr);
+ }
+
+
+ /**
+ * Validates that store/replace/delete operation against partitions result in the expected events
+ * being published to the event stream.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampTransactionException
+ */
+ @Test
+ public void partitionOperationsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+
+ // Create the vertices and edge objects that we need to create a partition.
+ ChampObject obj1 = ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .build();
+
+ ChampObject obj2 = ChampObject.create()
+ .ofType("bar")
+ .withKey("123")
+ .withProperty("p3", "v3")
+ .build();
+
+ // Now, create an edge object and write it to the graph data store.
+ ChampRelationship rel = new ChampRelationship.Builder(obj1, obj2, "relationship")
+ .property("property-1", "value-1")
+ .property("property-2", "value-2")
+ .build();
+
+ // Now, create our partition object and store it in the graph.
+ ChampPartition partition = ChampPartition.create()
+ .withObject(obj1)
+ .withObject(obj2)
+ .withRelationship(rel)
+ .build();
+ testGraph.storePartition(partition, Optional.empty());
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected STORE event.", loggedEventStr.contains("STORE"));
+ assertTrue("Entity type for store event was not a partition.", loggedEventStr.contains("partition"));
+
+ // Now, delete our partition.
+ testGraph.deletePartition(partition, Optional.empty());
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected DELETE event.", loggedEventStr.contains("DELETE"));
+ assertTrue("Entity type for store event was not a partition.", loggedEventStr.contains("partition"));
+ }
+
+
+ /**
+ * This test validates that performing partition operations in the case where the data to be
+ * forwarded to the event stream is unavailable results in no event being generated, but
+ * does not otherwise create issues.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampTransactionException
+ */
+ @Test
+ public void partitionOperationsWithNullsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException, ChampTransactionException {
+
+ // Set up our graph to simulate a failure to retrieve some of the data we need to generate
+ // events.
+ testGraph.returnNulls();
+
+ // Create all of the objects we need to create a partition, and store the partition
+ // in the graph.
+ ChampObject obj1 = ChampObject.create()
+ .ofType("foo")
+ .withKey("123")
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .build();
+
+ ChampObject obj2 = ChampObject.create()
+ .ofType("bar")
+ .withKey("123")
+ .withProperty("p3", "v3")
+ .build();
+
+ ChampRelationship rel = new ChampRelationship.Builder(obj1, obj2, "relationship")
+ .property("property-1", "value-1")
+ .property("property-2", "value-2")
+ .build();
+
+ ChampPartition partition = ChampPartition.create()
+ .withObject(obj1)
+ .withObject(obj2)
+ .withRelationship(rel)
+ .build();
+ testGraph.storePartition(partition, Optional.empty());
+
+ // Check our simulated event stream to see if an an event log was produced.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Store partition event should not have been logged to the event stream", loggedEventStr);
+ }
+
+
+ /**
+ * Validates that store/replace/delete operation against vertex indexes result in the expected
+ * events being published to the event stream.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampIndexNotExistsException
+ */
+ @Test
+ public void indexOperationsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException,
+ ChampIndexNotExistsException {
+
+ // Create an index object and store it in the graph.
+ ChampObjectIndex objIndex = ChampObjectIndex.create()
+ .ofName("myIndex")
+ .onType("type")
+ .forField("myField")
+ .build();
+ testGraph.storeObjectIndex(objIndex);
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected STORE event.", loggedEventStr.contains("STORE"));
+ assertTrue("Entity type for store event was not a vertex index.", loggedEventStr.contains("objectIndex"));
+
+ // Now, delete our partition.
+ testGraph.deleteObjectIndex("myIndex");
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected DELETE event.", loggedEventStr.contains("DELETE"));
+ assertTrue("Entity type for store event was not a vertex index.", loggedEventStr.contains("objectIndex"));
+ }
+
+ /**
+ * This test validates that performing index operations in the case where the data to be
+ * forwarded to the event stream is unavailable results in no event being generated, but
+ * does not otherwise create issues.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampIndexNotExistsException
+ */
+ @Test
+ public void indexOperationsWithNullsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException,
+ ChampIndexNotExistsException {
+
+ // Set up our graph to simulate a failure to retrieve some of the data we need to generate
+ // events.
+ testGraph.returnNulls();
+
+ // Create an index object and store it in the graph.
+ ChampObjectIndex objIndex = ChampObjectIndex.create()
+ .ofName("myIndex")
+ .onType("type")
+ .forField("myField")
+ .build();
+ testGraph.storeObjectIndex(objIndex);
+
+ // Check our simulated event stream to see if an an event log was produced.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Now, delete our index.
+ testGraph.deleteObjectIndex("myIndex");
+
+ // Check our simulated event stream to see if an an event log was produced.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Delete partition event should not have been logged to the event stream", loggedEventStr);
+ }
+
+
+ /**
+ * This test validates that performing relationship index operations in the case where
+ * the data to be forwarded to the event stream is unavailable results in no event being
+ * generated, but does not otherwise create issues.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampIndexNotExistsException
+ */
+ @Test
+ public void relationshipIndexOperationsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException,
+ ChampIndexNotExistsException {
+
+ // Create a relationship index object and store it in the graph.
+ ChampRelationshipIndex relIndex = ChampRelationshipIndex.create()
+ .ofName("myIndex")
+ .onType("type")
+ .forField("myField")
+ .build();
+ testGraph.storeRelationshipIndex(relIndex);
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected STORE event.", loggedEventStr.contains("STORE"));
+ assertTrue("Entity type for store event was not a relationship index.", loggedEventStr.contains("relationshipIndex"));
+
+ // Now, delete our partition.
+ testGraph.deleteRelationshipIndex("myIndex");
+
+ // Retrieve the next event from the event stream and validate that it is what we expect.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Expected DELETE event.", loggedEventStr.contains("DELETE"));
+ assertTrue("Entity type for store event was not a relationship index.", loggedEventStr.contains("relationshipIndex"));
+ }
+
+
+ /**
+ * This test validates that performing index operations in the case where the data to be
+ * forwarded to the event stream is unavailable results in no event being generated, but
+ * does not otherwise create issues.
+ *
+ * @throws ChampMarshallingException
+ * @throws ChampSchemaViolationException
+ * @throws ChampObjectNotExistsException
+ * @throws InterruptedException
+ * @throws JsonParseException
+ * @throws JsonMappingException
+ * @throws IOException
+ * @throws ChampUnmarshallingException
+ * @throws ChampRelationshipNotExistsException
+ * @throws ChampIndexNotExistsException
+ */
+ @Test
+ public void relationshipIndexOperationsWithNullsTest() throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException,
+ InterruptedException,
+ JsonParseException,
+ JsonMappingException,
+ IOException,
+ ChampUnmarshallingException,
+ ChampRelationshipNotExistsException,
+ ChampIndexNotExistsException {
+
+ // Set up our graph to simulate a failure to retrieve some of the data we need to generate
+ // events.
+ testGraph.returnNulls();
+
+ // Create a relationship index object and store it in the graph.
+ ChampRelationshipIndex relIndex = ChampRelationshipIndex.create()
+ .ofName("myIndex")
+ .onType("type")
+ .forField("myField")
+ .build();
+
+ testGraph.storeRelationshipIndex(relIndex);
+
+ // Check our simulated event stream to see if an an event log was produced.
+ String loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Now, delete our index.
+ testGraph.deleteRelationshipIndex("myIndex");
+
+ // Check our simulated event stream to see if an event log was produced.
+ loggedEventStr = producer.eventStream.poll(5000, TimeUnit.MILLISECONDS);
+
+ // Validate that we did not get an event from the stream.
+ assertNull("Delete partition event should not have been logged to the event stream", loggedEventStr);
+ }
+
+
+ /**
+ * This is a simple graph stub that extends our {@link AbstractLoggingChampGraph} class which
+ * we can use to validate that log events get generated without worrying about having a real
+ * underlying graph.
+ */
+ private class TestGraph extends AbstractLoggingChampGraph {
+
+ /** If set, this causes simulated retrieve operations to fail. */
+ private boolean returnNulls = false;
+
+
+ protected TestGraph(Map<String, Object> properties) {
+ super(properties);
+ }
+
+ public void returnNulls() {
+ returnNulls = true;
+ }
+
+ @Override
+ public void shutdown() {
+ if(returnNulls) {
+ publisherPool = null;
+ }
+ super.shutdown();
+ }
+
+ @Override
+ public ChampObject executeStoreObject(ChampObject object, Optional<ChampTransaction> transaction)
+ throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException {
+
+ if(!returnNulls) {
+ return object;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public ChampObject executeReplaceObject(ChampObject object, Optional<ChampTransaction> transaction)
+ throws ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampObjectNotExistsException {
+
+ if(!returnNulls) {
+ return object;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException {
+ return retrieveObject(key, Optional.empty());
+ }
+
+ @Override
+ public Optional<ChampObject> retrieveObject(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException {
+
+ if(!returnNulls) {
+ return(Optional.of(ChampObject.create()
+ .ofType("foo")
+ .withKey(key)
+ .build()));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public void executeDeleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException {
+
+ }
+
+ @Override
+ public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) {
+ return queryObjects(queryParams, Optional.empty());
+ }
+
+
+ @Override
+ public Stream<ChampObject> queryObjects(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) {
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public ChampRelationship executeStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException,
+ ChampMarshallingException,
+ ChampObjectNotExistsException,
+ ChampSchemaViolationException,
+ ChampRelationshipNotExistsException {
+
+ if(!returnNulls) {
+ return relationship;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public ChampRelationship executeReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException,
+ ChampMarshallingException,
+ ChampSchemaViolationException,
+ ChampRelationshipNotExistsException {
+
+ if(!returnNulls) {
+ return relationship;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Optional<ChampRelationship> retrieveRelationship(Object key) throws ChampUnmarshallingException {
+ return retrieveRelationship(key, Optional.empty());
+ }
+
+ @Override
+ public Optional<ChampRelationship> retrieveRelationship(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException {
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public void executeDeleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException {
+ // Not used by any tests.
+ }
+
+ @Override
+ public Stream<ChampRelationship> retrieveRelationships(ChampObject object)
+ throws ChampUnmarshallingException, ChampObjectNotExistsException {
+ return retrieveRelationships(object, Optional.empty());
+ }
+
+ @Override
+ public Stream<ChampRelationship> retrieveRelationships(ChampObject object, Optional<ChampTransaction> transaction)
+ throws ChampUnmarshallingException, ChampObjectNotExistsException {
+
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) {
+ return queryRelationships(queryParams, Optional.empty());
+ }
+
+ @Override
+ public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) {
+
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public ChampPartition executeStorePartition(ChampPartition partition, Optional<ChampTransaction> transaction)
+ throws ChampSchemaViolationException,
+ ChampRelationshipNotExistsException,
+ ChampMarshallingException,
+ ChampObjectNotExistsException {
+
+ if(!returnNulls) {
+ return partition;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void executeDeletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) {
+ // Not used by any tests.
+ }
+
+ @Override
+ public void executeStoreObjectIndex(ChampObjectIndex index) {
+ // Not used by any tests.
+ }
+
+ @Override
+ public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName) {
+
+ if(!returnNulls) {
+ return Optional.of(ChampObjectIndex.create()
+ .ofName(indexName)
+ .onType("doesnt matter")
+ .forField("doesnt matter")
+ .build());
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public Stream<ChampObjectIndex> retrieveObjectIndices() {
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException {
+ // Not used by any tests.
+ }
+
+ @Override
+ public void executeStoreRelationshipIndex(ChampRelationshipIndex index) {
+ // Not used by any tests.
+ }
+
+ @Override
+ public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName) {
+ if(!returnNulls) {
+ return Optional.of(ChampRelationshipIndex.create()
+ .ofName(indexName)
+ .onType("doesnt matter")
+ .forField("doesnt matter")
+ .build());
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public Stream<ChampRelationshipIndex> retrieveRelationshipIndices() {
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public void executeDeleteRelationshipIndex(String indexName)
+ throws ChampIndexNotExistsException {
+ // Not used by any tests.
+ }
+
+ @Override
+ public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException {
+ // Not used by any tests.
+ }
+
+ @Override
+ public ChampSchema retrieveSchema() {
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public void updateSchema(ChampObjectConstraint objectConstraint)
+ throws ChampSchemaViolationException {
+ // Not used by any tests.
+ }
+
+ @Override
+ public void updateSchema(ChampRelationshipConstraint schema)
+ throws ChampSchemaViolationException {
+ // Not used by any tests.
+ }
+
+ @Override
+ public void deleteSchema() {
+ // Not used by any tests.
+ }
+
+ @Override
+ public ChampCapabilities capabilities() {
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public ChampTransaction openTransaction() {
+ // Not used by any tests.
+ return null;
+ }
+
+ @Override
+ public void commitTransaction(ChampTransaction transaction) {
+ // Not used by any tests.
+
+ }
+
+ @Override
+ public void rollbackTransaction(ChampTransaction transaction) {
+ // Not used by any tests.
+ }
+ }
+
+ private class InMemoryPublisher implements EventPublisher {
+
+ public BlockingQueue<String> eventStream = new ArrayBlockingQueue<String>(50);
+ public BlockingQueue<String> failedMsgs = new ArrayBlockingQueue<String>(10);
+ private boolean failMode=false;
+
+
+ public void enterFailMode() {
+ failMode=true;
+ }
+
+ @Override
+ public int sendSync(String partitionKey, String message) throws Exception {
+
+ if(!failMode) {
+ eventStream.add(message);
+ return 0;
+ } else {
+ failedMsgs.add(message);
+ throw new IOException("nope");
+ }
+ }
+
+ @Override
+ public int sendSync(String partitionKey, Collection<String> messages) throws Exception {
+
+ for(String msg : messages) {
+ if(!failMode) {
+ eventStream.add(msg);
+ return 0;
+ } else {
+ failedMsgs.add(msg);
+ throw new IOException("nope");
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int sendSync(String message) throws Exception {
+ if(!failMode) {
+ eventStream.add(message);
+ return 0;
+ } else {
+ failedMsgs.add(message);
+ throw new IOException("nope");
+ }
+ }
+
+ @Override
+ public int sendSync(Collection<String> messages) throws Exception {
+
+ for(String msg : messages) {
+ if(!failMode) {
+ eventStream.add(msg);
+ return 0;
+ } else {
+ failedMsgs.add(msg);
+ throw new IOException("nope");
+ }
+ }
+ return 0;
+ }
+ @Override
+ public void sendAsync(String partitionKey, String message) throws Exception {
+ if(!failMode) {
+ eventStream.add(message);
+ } else {
+ failedMsgs.add(message);
+ throw new IOException("nope");
+ }
+ }
+ @Override
+ public void sendAsync(String partitionKey, Collection<String> messages) throws Exception {
+ for(String msg : messages) {
+ if(!failMode) {
+ eventStream.add(msg);
+ } else {
+ failedMsgs.add(msg);
+ throw new IOException("nope");
+ }
+ }
+ }
+ @Override
+ public void sendAsync(String message) throws Exception {
+ if(!failMode) {
+ eventStream.add(message);
+ } else {
+ failedMsgs.add(message);
+ throw new IOException("nope");
+ }
+ }
+ @Override
+ public void sendAsync(Collection<String> messages) throws Exception {
+ for(String msg : messages) {
+ if(!failMode) {
+ eventStream.add(msg);
+ } else {
+ failedMsgs.add(msg);
+ throw new IOException("nope");
+ }
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ // TODO Auto-generated method stub
+
+ }
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/exceptions/ChampExceptionTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/exceptions/ChampExceptionTest.java
new file mode 100644
index 0000000..f7a32f7
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/exceptions/ChampExceptionTest.java
@@ -0,0 +1,150 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.exceptions;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class ChampExceptionTest {
+
+ @Test
+ public void testChampIndexNotExistsException() {
+ final ChampIndexNotExistsException e1 = new ChampIndexNotExistsException();
+
+ assertTrue(e1.getMessage() == null);
+
+ final ChampIndexNotExistsException e2 = new ChampIndexNotExistsException("foo");
+
+ assertTrue(e2.getMessage().equals("foo"));
+
+ final ChampIndexNotExistsException e3 = new ChampIndexNotExistsException(e2);
+
+ assertTrue(e3.getCause().equals(e2));
+
+ final ChampIndexNotExistsException e4 = new ChampIndexNotExistsException("foo", e3);
+
+ assertTrue(e4.getMessage().equals("foo"));
+ assertTrue(e4.getCause().equals(e3));
+ }
+
+ @Test
+ public void testChampMarshallingException() {
+ final ChampMarshallingException e1 = new ChampMarshallingException();
+
+ assertTrue(e1.getMessage() == null);
+
+ final ChampMarshallingException e2 = new ChampMarshallingException("foo");
+
+ assertTrue(e2.getMessage().equals("foo"));
+
+ final ChampIndexNotExistsException e3 = new ChampIndexNotExistsException(e2);
+
+ assertTrue(e3.getCause().equals(e2));
+
+ final ChampMarshallingException e4 = new ChampMarshallingException("foo", e3);
+
+ assertTrue(e4.getMessage().equals("foo"));
+ assertTrue(e4.getCause().equals(e3));
+ }
+
+ @Test
+ public void testChampObjectNotExistsException() {
+ final ChampObjectNotExistsException e1 = new ChampObjectNotExistsException();
+
+ assertTrue(e1.getMessage() == null);
+
+ final ChampObjectNotExistsException e2 = new ChampObjectNotExistsException("foo");
+
+ assertTrue(e2.getMessage().equals("foo"));
+
+ final ChampIndexNotExistsException e3 = new ChampIndexNotExistsException(e2);
+
+ assertTrue(e3.getCause().equals(e2));
+
+ final ChampObjectNotExistsException e4 = new ChampObjectNotExistsException("foo", e3);
+
+ assertTrue(e4.getMessage().equals("foo"));
+ assertTrue(e4.getCause().equals(e3));
+ }
+
+ @Test
+ public void testChampRelationshipNotExistsException() {
+ final ChampRelationshipNotExistsException e1 = new ChampRelationshipNotExistsException();
+
+ assertTrue(e1.getMessage() == null);
+
+ final ChampRelationshipNotExistsException e2 = new ChampRelationshipNotExistsException("foo");
+
+ assertTrue(e2.getMessage().equals("foo"));
+
+ final ChampIndexNotExistsException e3 = new ChampIndexNotExistsException(e2);
+
+ assertTrue(e3.getCause().equals(e2));
+
+ final ChampRelationshipNotExistsException e4 = new ChampRelationshipNotExistsException("foo", e3);
+
+ assertTrue(e4.getMessage().equals("foo"));
+ assertTrue(e4.getCause().equals(e3));
+ }
+
+ @Test
+ public void testChampSchemaViolationException() {
+ final ChampSchemaViolationException e1 = new ChampSchemaViolationException();
+
+ assertTrue(e1.getMessage() == null);
+
+ final ChampSchemaViolationException e2 = new ChampSchemaViolationException("foo");
+
+ assertTrue(e2.getMessage().equals("foo"));
+
+ final ChampIndexNotExistsException e3 = new ChampIndexNotExistsException(e2);
+
+ assertTrue(e3.getCause().equals(e2));
+
+ final ChampSchemaViolationException e4 = new ChampSchemaViolationException("foo", e3);
+
+ assertTrue(e4.getMessage().equals("foo"));
+ assertTrue(e4.getCause().equals(e3));
+ }
+
+ @Test
+ public void testChampUnmarshallingException() {
+ final ChampUnmarshallingException e1 = new ChampUnmarshallingException();
+
+ assertTrue(e1.getMessage() == null);
+
+ final ChampUnmarshallingException e2 = new ChampUnmarshallingException("foo");
+
+ assertTrue(e2.getMessage().equals("foo"));
+
+ final ChampIndexNotExistsException e3 = new ChampIndexNotExistsException(e2);
+
+ assertTrue(e3.getCause().equals(e2));
+
+ final ChampUnmarshallingException e4 = new ChampUnmarshallingException("foo", e3);
+
+ assertTrue(e4.getMessage().equals("foo"));
+ assertTrue(e4.getCause().equals(e3));
+ }
+
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ExportTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ExportTest.java
new file mode 100644
index 0000000..bda6122
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ExportTest.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.ie;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+
+public class ExportTest {
+
+ @Test
+ public void testGraphMLExport() {
+
+ final GraphMLImporterExporter ie = new GraphMLImporterExporter();
+ final ChampAPI api = ChampAPI.Factory.newInstance("IN_MEMORY");
+
+ ie.importData(api, getClass().getClassLoader().getResourceAsStream("import-test.graphml"));
+
+ ie.exportData(api.getGraph("unit-test"), System.out);
+
+ api.shutdown();
+ }
+}
diff --git a/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ImportTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ImportTest.java
new file mode 100644
index 0000000..67fdb19
--- /dev/null
+++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ImportTest.java
@@ -0,0 +1,94 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.champcore.ie;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import org.junit.Test;
+import org.onap.aai.champcore.ChampAPI;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+
+public class ImportTest {
+
+ private final String GRAPH_NAME = "unit-test";
+
+ @Test
+ public void testGraphMLImport() throws ChampTransactionException, AssertionError {
+
+ final GraphMLImporterExporter importer = new GraphMLImporterExporter();
+ final ChampAPI api = ChampAPI.Factory.newInstance("IN_MEMORY");
+
+ importer.importData(api, getClass().getClassLoader().getResourceAsStream("import-test.graphml"));
+
+ final ChampGraph graph = api.getGraph(GRAPH_NAME);
+
+ graph.queryObjects(Collections.emptyMap(), Optional.empty()).forEach(object -> {
+ final Optional<String> nameOpt = object.getProperty("name");
+ final Optional<Boolean> studentOpt = object.getProperty("student");
+ final Optional<Long> worthOpt = object.getProperty("worth");
+ final Optional<Integer> ageOpt = object.getProperty("age");
+ final Optional<Float> heightOpt = object.getProperty("height");
+ final Optional<Double> weightOpt = object.getProperty("weight");
+ final Optional<String> favoriteColorOpt = object.getProperty("favoriteColor");
+
+ final String name = nameOpt.get();
+
+ if (name.equals("Champ")) {
+ assertTrue(!studentOpt.isPresent());
+ assertTrue(!ageOpt.isPresent());
+ assertTrue(!worthOpt.isPresent());
+ assertTrue(!heightOpt.isPresent());
+ assertTrue(!weightOpt.isPresent());
+ assertTrue(favoriteColorOpt.get().equals("green"));
+ } else if (name.equals("Max")) {
+ assertTrue(!studentOpt.isPresent());
+ assertTrue(!ageOpt.isPresent());
+ assertTrue(!worthOpt.isPresent());
+ assertTrue(!heightOpt.isPresent());
+ assertTrue(!weightOpt.isPresent());
+ assertTrue(favoriteColorOpt.get().equals("red"));
+ } else if (name.equals("Ace")) {
+ assertTrue(studentOpt.get());
+ assertTrue(worthOpt.get().equals(50000L));
+ assertTrue(ageOpt.get().equals(21));
+ assertTrue(heightOpt.get().equals(72.5f));
+ assertTrue(weightOpt.get().equals(180.5d));
+ assertTrue(favoriteColorOpt.get().equals("yellow"));
+ } else if (name.equals("Fido")) {
+ assertTrue(!studentOpt.isPresent());
+ assertTrue(!ageOpt.isPresent());
+ assertTrue(!worthOpt.isPresent());
+ assertTrue(!heightOpt.isPresent());
+ assertTrue(!weightOpt.isPresent());
+ assertTrue(favoriteColorOpt.get().equals("blue"));
+ } else {
+ throw new AssertionError("Unknown object " + name + " - update unit test");
+ }
+ });
+
+ api.shutdown();
+ }
+}
diff --git a/champ-lib/champ-core/src/test/resources/import-test.graphml b/champ-lib/champ-core/src/test/resources/import-test.graphml
new file mode 100644
index 0000000..fd13b6b
--- /dev/null
+++ b/champ-lib/champ-core/src/test/resources/import-test.graphml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+ <key id="d0" for="node" attr.name="student" attr.type="boolean"/>
+ <key id="d1" for="node" attr.name="worth" attr.type="long"/>
+ <key id="d2" for="node" attr.name="age" attr.type="int"/>
+ <key id="d3" for="node" attr.name="height" attr.type="float"/>
+ <key id="d4" for="node" attr.name="weight" attr.type="double"/>
+ <key id="d5" for="node" attr.name="favoriteColor" attr.type="string">
+ <default>green</default>
+ </key>
+ <key id="d6" for="node" attr.name="name" attr.type="string"/>
+ <key id="d7" for="edge" attr.name="at" attr.type="long"/>
+ <key id="d8" for="node" attr.name="type" attr.type="string"/>
+ <key id="d9" for="edge" attr.name="type" attr.type="string"/>
+ <graph id="unit-test" edgedefault="directed">
+ <node id="n0">
+ <data key="d0">true</data>
+ <data key="d1">50000</data>
+ <data key="d2">21</data>
+ <data key="d3">72.5</data>
+ <data key="d4">180.5</data>
+ <data key="d5">yellow</data>
+ <data key="d6">Ace</data>
+ <data key="d8">Dog</data>
+ </node>
+ <node id="n1">
+ <data key="d6">Champ</data>
+ <data key="d8">Dog</data>
+ </node>
+ <node id="n2">
+ <data key="d5">blue</data>
+ <data key="d6">Fido</data>
+ <data key="d8">Dog</data>
+ </node>
+ <node id="n3">
+ <data key="d5">red</data>
+ <data key="d6">Max</data>
+ <data key="d8">Dog</data>
+ </node>
+ <edge id="e0" source="n0" target="n2">
+ <data key="d7">12348234</data>
+ <data key="d9">Dog</data>
+ </edge>
+ <edge id="e3" source="n3" target="n2">
+ <data key="d9">Dog</data>
+ </edge>
+ </graph>
+</graphml> \ No newline at end of file
diff --git a/champ-lib/champ-core/src/test/resources/logback.xml b/champ-lib/champ-core/src/test/resources/logback.xml
new file mode 100644
index 0000000..72cd644
--- /dev/null
+++ b/champ-lib/champ-core/src/test/resources/logback.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ ============LICENSE_START==========================================
+ org.onap.aai
+ ===================================================================
+ Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ Copyright © 2017 Amdocs
+ ===================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ============LICENSE_END============================================
+ ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+-->
+<configuration>
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d %-5level [%thread] %logger{255}: %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <logger name="com.thinkaurelius.titan" level="OFF"/>
+ <logger name="com.netflix.astyanax" level="OFF"/>
+ <logger name="com.datastax" level="ERROR"/>
+ <logger name="org.apache.hadoop" level="ERROR"/>
+ <logger name="org.apache.zookeeper" level="ERROR"/>
+
+ <root level="INFO">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>