diff options
Diffstat (limited to 'champ-lib/champ-core')
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> |