diff options
author | michaere <michaere@amdocs.com> | 2018-03-05 16:33:32 +0000 |
---|---|---|
committer | michaere <michaere@amdocs.com> | 2018-03-07 11:17:22 +0000 |
commit | c74f7b13b573386e70c10721fc391624ee792ed6 (patch) | |
tree | b44995474ff938b4b03c9b234f95b71bc75d6b79 | |
parent | 9fc28cff11a4b570618c0f533ce9de6209a5dd0c (diff) |
Port champ-microservice project restructure
Includes project restructure and introduction of a parent pom. The
original source folder and core functionality is now held within champ-lib, with champ-service
forming the ajsc microservice from which it injects champ-lib core
functionality.
Issue-ID: AAI-813
Change-Id: I2ce0c4a70e485665276e7955572de23969deb706
Signed-off-by: michaere <michaere@amdocs.com>
238 files changed, 14697 insertions, 4990 deletions
@@ -9,392 +9,704 @@ Champ is an abstraction from underlying graph storage systems that A&AI would ot Building Champ -------------- -Good ol' 'mvn clean install' does the trick. +To build Champ run the following maven command from the project's root level pom directory: + + mvn clean install + +Deploying The Microservice +-------------------------- + +Push the Docker image that you have built to your Docker repository and pull it down to the location from which you will be running the service. + +**Create the following directories on the host machine:** + + ../logs + ../appconfig + ../appconfig/auth + ../dynamic/conf + +You will be mounting these as data volumes when you start the Docker container. + +#### Configuring the Microservice + +Create beans file **../dynamic/conf/champ-beans.xml** + +Example: + + <beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util.xsd + "> + + <util:constant id="DEFAULT_BATCH_SIZE" static-field="com.att.ecomp.event.client.DMaaPEventPublisher.DEFAULT_BATCH_SIZE" /> + <util:constant id="DEFAULT_BATCH_AGE" static-field="com.att.ecomp.event.client.DMaaPEventPublisher.DEFAULT_BATCH_AGE" /> + <util:constant id="DEFAULT_BATCH_DELAY" static-field="com.att.ecomp.event.client.DMaaPEventPublisher.DEFAULT_BATCH_DELAY" /> + + + <bean id="champEventPublisher" class="com.att.ecomp.event.client.DMaaPEventPublisher" > + <constructor-arg name="host" value="<%= @CHAMP_EVBUS_HOSTS %>" /> + <constructor-arg name="topic" value="<%= @CHAMP_EVENT_TOPIC %>" /> + <constructor-arg name="username" value="<%= @CHAMP_DMAAP_API_KEY %>" /> + <constructor-arg name="password" value="<%= @CHAMP_DMAAP_API_SECRET %>" /> + <constructor-arg name="maxBatchSize" ref="DEFAULT_BATCH_SIZE" /> + <constructor-arg name="maxAgeMs" ref="DEFAULT_BATCH_AGE" /> + <constructor-arg name="delayBetweenBatchesMs" ref="DEFAULT_BATCH_DELAY" /> + <constructor-arg name="transportType" value="HTTPAUTH" /> + </bean> + + <!-- Graph Implementation Configuration--> + <util:map id="props" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.Object"> + <entry key="champcore.event.stream.buffer.capacity" value="50" value-type="java.lang.Integer"/> + <entry key="champcore.event.stream.publisher-pool-size" value="10" value-type="java.lang.Integer"/> + <entry key="champcore.event.stream.publisher" value-ref="champEventPublisher"/> + + <entry key="graph.name" value="<%= @CHAMP_GRAPH_NAME %>"/> + <entry key="storage.backend" value="<%= @CHAMP_STORAGE_BACKEND_DB %>"/> + <entry key="storage.hostname" value="<%= @CHAMP_GRAPH_HOST %>"/> + + <!-- Hbase Config --> + <entry key="storage.hbase.ext.hbase.zookeeper.property.clientPort" value="<%= @CHAMP_GRAPH_PORT %>"/> + <entry key="storage.hbase.ext.zookeeper.znode.parent" value="/hbase-unsecure"/> + + <!-- Cassandra Config --> + <entry key="storage.port" value="<%= @CHAMP_GRAPH_PORT %>"/> + </util:map> + + <!-- Janus Implementation --> + <bean id="graphBuilder" class="org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl$Builder"> + <constructor-arg value="<%= @CHAMP_GRAPH_NAME %>"/> + <constructor-arg ref="props" /> + </bean> + <bean id="graphImpl" class="org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl"> + <constructor-arg ref="graphBuilder" /> + </bean> + <bean id="champRestService" class="org.onap.champ.ChampRESTAPI" > + <constructor-arg ref="graphImpl" /> + <constructor-arg name="txTimeOutInSec" value="300" /> + </bean> + </beans> + +Create configuration file **../appconfig/auth/champ-policy.json** + +This policy file defines which client certificates are authorized to use the service's APIs. An example policy file follows: + + { + "roles": [ + { + "name": "admin", + "functions": [ + { + "name": "search", "methods": [ { "name": "GET" },{ "name": "DELETE" }, { "name": "PUT" }, { "name": "POST" } ] + } + ], + "users": [ + { + "username": "CN=admin, OU=My Organization Unit, O=, L=Sometown, ST=SomeProvince, C=CA" + } + ] + } + ] + } + +Create keystore file **../appconfig/auth/tomcat\_keystore** +_tomcat\_keystore_ + +Create a keystore with this name containing whatever CA certificates that you want your instance of the CHAMP service to accept for HTTPS traffic. + +#### Start the service + +You can now start the Docker container in the following manner: + + docker run -d \ + -p 9520:9520 \ + -e CONFIG_HOME=/opt/app/champ-service/config/ \ + -e KEY_STORE_PASSWORD={{obfuscated password}} \ + -e KEY_MANAGER_PASSWORD=OBF:{{obfuscated password}} \ + -v /<path>/logs:/opt/aai/logroot/AAI-CHAMP \ + -v /<path>/appconfig:/opt/app/champ-service/config \ + --name champ-service \ + {{your docker repo}}/champ-service + +Where, + + {{your docker repo}} = The Docker repository you have published your CHAMP Service image to. + {{obfuscated password}} = The password for your key store/key manager after running it through the Jetty obfuscation tool. API Specification ----------------- -Champ has CRUD methods for: +Champ has methods for: 1) Objects 2) Relationships -3) Partitions (subgraphs) -3) Indices (on object and relationship properties) -4) Schemas +3) Transactions -For each of these types, we offer builders and a more user-friendly fluent interface. - -In the future we plan on adding in traversals, but at the moment that is outside the scope of Champ. If you have suggestions on how this should be implemented, we look forward to your pull request. +In the future we plan on adding in partitions, indicies, schemas, and traversals, but at the moment that is outside the scope of Champ. If you have suggestions on how this should be implemented, we look forward to your pull request. API Implementations ------------------- -Champ ships with a simple in-memory implementation as well as a Titan implementation. We recommend the in-memory implementation for unit testing and prototyping. If you would like to have your implementation referenced in this readme, please create a pull-request. Please note that all implementations will reside in their own repository - not in the Champ repository. - -Usage ------ - -### ChampAPI - -The ChampAPI interface is basically just for tracking and properly shutting down multiple graph instances. If you need this functionality, use the ChampAPI. However, if you only ever access 1 graph, you may choose to use a single ChampGraph. - -For getting started quickly, use the ChampAPI.Factory or ChampGraph.Factory to create either an In-memory implementation (for dev/test) or if you're running Titan locally, you can start a Titan instance. For complex environments, each ChampGraph implementation will vary - the Titan implementation is described below. - -### ChampGraph - -This is the meat and potatoes of Champ. It contains all of the CRUD methods mentioned above for Objects, Relationships, Partitions, Indices, and Schemas. Each implementation varies in how you instantiate it. The ones that ship with Champ are described below. - -#### In-memory ChampGraph - -Simply: - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(ChampGraph.Type.IN_MEMORY, "someGraphName"); - -//Do stuff with graph +Champ ships with both Titan and Janus implementations. These are switchable after deployment, but the champ-beans.xml file needs to be changed and the champ-service must be restarted. -graph.shutdown(); +Event Generation +---------------- -``` +Champ can be configured to generate a notification whenever it is used to modify data in the graph. The notification comes in the form of an event which is posted to the **champRawEvents** Event Bus topic. This event stream allows downstream clients to be notified about objects and relationships which are added/modified/deleted in the graph. -or: +The following configuration parameters define the behaviour of the event generation feature: -``` -final ChampAPI api = ChampAPI.Factory.newInstance(ChampGraph.Type.IN_MEMORY); -final ChampGraph dogsGraph = api.getGraph("dogsGraph"); -final ChampGraph catsGraph = api.getGraph("catsGraph"); +- **champ.event.stream.publisher**: _EventClientPublisher_ instance to use for forwarding events to the event stream (see below). +- **champ.event.stream.publisher-pool-size**: Optional: number of worker threads to use for event publishing. +- **champ.event.stream.buffer.capacity**: Optional: maximum number of events which may be enqueued waiting to be published at any given time. + -api.shutdown(); //This will shutdown all graphs started by api.getGraph(String) +The following examples illustrate snippets of typical spring-beans configuration file which instantiate a producer (if your client is not spring enabled then you may just directly instantiate an _EventBusPublisher_ - refer to the _ECOMP Event Bus Client_ library for details): -``` +_Instantiating an event producer backed by a native Kafka implementation:_ -#### Titan ChampGraph + <!-- Event publisher to pass to the Champ library for logging raw graph events. --> + <bean id="champEventPublisher" class="com.att.ecomp.event.client.KafkaEventPublisher" > + <constructor-arg name="hosts" value="1.2.3.4:9092, 5.6.7.8:9092, 9.10.11.12:9092" /> + <constructor-arg name="topic" value="champRawEvents" /> + </bean> -For a Titan instance running on top of Cassandra locally, simply: +_Instantiating an event producer backed by a DMaaP Client implementation:_ -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(ChampGraph.Type.TITAN, "dogsGraph"); + <bean id="champEventPublisher" class="com.att.ecomp.event.client.DMaaPEventPublisher" > + <constructor-arg name="urlList" value="1.2.3.4, 5.6.7.8, 9.10.11.12" /> + <constructor-arg name="topic" value="champRawEvents" /> + <constructor-arg name="apiKey" value="OBF:1r2v1qc51i0r1l6n1m4q1jew1bpt1lkp1ll11bot1jee1m7o1l6n1i0z1qax1r53" /> + <constructor-arg name="apiSecret" value="OBF:1ro81caa1myq1mzs1nx31kfl1d2q1zsp1yt81nz31f8h1hmd1hmx1fa51nxb1yte1zt11d3g1kct1nzb1mxi1myk1cb01rqe" /> + </bean> -//Do stuff with graph + -graph.shutdown(); - -``` -or: - -``` -final ChampAPI api = ChampAPI.Factory.newInstance(ChampGraph.Type.TITAN); -final ChampGraph dogsGraph = api.getGraph("dogsGraph"); -final ChampGraph cats Graph = api.getGraph("catsGraph"); - -api.shutdown(); //This will shutdown all graph started by api.getGraph(String); - -``` - -For more complex/customized configurations: +Usage +----- -``` - final ChampGraph graph = new TitanChampGraphImpl.Builder(graphName) - .property("storage.backend", "cassandrathrift") - .property("storage.hostname", "localhost") - .build(); -``` +### Echo -The calls to .property(String, String) accept all configuration options found [here](http://s3.thinkaurelius.com/docs/titan/1.0.0/titan-config-ref.html) + URL: https://<host>:9522/services/echo-service/echo/<input> + Method: GET + Success Response: 200 OK -You could also implement the ChampAPI interface to manage multiple graphs connected to this Titan cluster. See the ChampAPIImpl class for an example of how to do this. -### Creating Objects +### Objects #### Create a new object - -``` -ChampObject.create() - .ofType("foo") //The "foo" type of object can be constrained by a ChampObjectConstraint - .withoutKey() //No key for this object indicates that the underlying Champ implementation should create this object - .withProperty("bar", "string") //Zero or more properties can be set on a ChampObject - .withProperty("baz", 30) - .build() -``` - -#### Copy an existing object - -``` -ChampObject.create() - .from(foo) //'foo' is a reference to a ChampObject - .withoutKey() - .withProperty("pi", 3.14f) - .build() -``` - -#### Persisting an object - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.storeObject(foo); //'foo' is a reference to a ChampObject -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - //Once your application is finished using it, call shutdown() - //to cleanup any loose ends -``` +Inserts a new object into the graph with the type and properties from the body of the request. Returns the object that was created, along with its assigned key and timestamps. + + URL: https://<host>:9522/services/champ-service/v1/objects + Method: POST + Body: + { + "type" : "test", + "properties" : { + "key1" : "val1", + "key2" : "val2" + } + } + + Success Response: + Code: 201 + Content: + { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "aai-created-ts": 1516731449014, + "aai-last-mod-ts": 1516731449014 + } + } #### Retrieve an object - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -final Optional<ChampObject> object = graph.retrieveObject("329847"); //Note that the key is usually only known by virtue of previously storing/retrieving/querying it - -graph.shutdown(); - -``` - -#### Query objects - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -final Stream<ChampObject> objects = graph.queryObjects(Collection.singletonMap("favoriteDog", "Ace")); - -objects.close(); //You must close the stream when you are finished with it -graph.shutdown(); - -``` - -### Creating Relationships +A GET request that returns the object with the given key + + URL: https://<host>:9522/services/champ-service/v1/objects/<key> + Method: GET + Success Response: + Code: 200 OK + Content: + { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "aai-created-ts": 1516731449014, + "aai-last-mod-ts": 1516731449014 + } + } + +#### Updating an object +Replace any of the properties with a PUT request, get the updated object back. Inclusion of timestamps is optional, but the request will be rejected if they do not match the DB. + + URL: https://<host>:9522/services/champ-service/v1/objects/<key> + Method: PUT + Content: + { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4", + "aai-created-ts": 1516731449014 + } + } + + Response: + Code: 200 OK + Content: + { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4", + "aai-created-ts": 1516731449014, + "aai-last-mod-ts": 1516730919213 + } + } + +#### Delete objects +Deletes the object from the graph if there are no connected relationships + + URL: https://<host>:9522/services/champ-service/v1/objects/<key> + Method: DELETE + Success Response: + Code: 200 OK + + + +#### Filtered object search +Get a list of objects filtered by key/value pairs + + URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val> + Method: GET + Success Response: + [ + { + "key": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb", + "type": "test2", + "properties": {} + } + ] + +Get a list of objects filtered by key/value pairs with specific properties + + URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val>&properties=<prop1>&properties=<prop2> + Method: GET + Success Response: + [ + { + "key": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb", + "type": "test2", + "properties": { + "key1": "val1", + "filter-sample": "yes" + } + } + ] + +Get a list of objects filtered by key/value pairs with all properties + + URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val>&properties=all + Method: GET + Success Response: + [ + { + "key": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb", + "type": "test2", + "properties": { + "key1": "val1", + "aai-uuid": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb", + "filter-sample": "yes" + } + } + ] + +### Relationships +Relationships are used to create a connection between two pre-existing objects. #### Create a new relationship - -In this example we create the relationship: - -dog eats dogPellets - -``` -ChampRelationship.create() - .ofType("eats") - .withoutKey() - .withSource() - .ofType("dog") - .withoutKey() - .withProperty("name", "champ") - .build() - .withTarget() - .ofType("dogPellets") - .withoutKey() - .withProperty("brand", "costco") - .build() - .withProperty("at", System.currentTimeMillis()) - .build() -``` - -#### Persisting a relationship - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.storeRelationship(champEatsCostcoFood); //'champEatsCostcoFood' is a reference to a ChampRelationship -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - //Once your application is finished using it, call shutdown() - //to cleanup any loose ends -``` - -#### Retrieving incident relationships - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -final Stream<ChampRelationship> relationships = graph.retrieveRelationships(ChampObject.create().withKey("foo").build()); - -relationships.close(); //You must close the stream when you are done with it -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - -``` - -#### Querying relationship - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -final Stream<ChampRelationship> relationships = graph.queryRelationships(Collections.singletonMap("favoriteHydrant", 42); - -relationships.close(); //You must close the stream when you are done with it -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - -``` - -### Creating partitions -#### Create a new partition - -Champ partitions are subgraphs (i.e. a collection of objects and relationships) -** Note: We are still in the proces of creating a fluent API for partitions ** - - -``` -ChampPartition.create() - .withObject( - ChampObject.create() - .ofType("dog") - .withoutKey() - .build() - ) - .withObject( - ChampObject.create() - .ofType("cat") - .withoutKey() - .build() - .withObject( - ChampObject.create() - .ofType("bird") - .withoutKey() - .build() - ) - .withRelationship( - ChampRelationship.create() - ... - .build() - ) - .build() -``` - -#### Persisting a partition - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.storePartition(dogsOnMyBlock); //'dogsOnMyBlock' is a reference to a ChampPartition -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - //Once your application is finished using it, call shutdown() - //to cleanup any loose ends -``` - -### Creating indices -#### Create an object index - -``` -ChampObjectIndex.create() - .ofName("dogName") - .onType("dog") - .forField("name") - .build() -``` - -#### Create a relationship index - -``` -ChampRelationshipIndex.create() - .ofName("eatsAtTime") - .onType("eats") - .forField("at") - .build() -``` - -#### Persisting an object index - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.storeObjectIndex(dogName); //'dogName' is a reference to a ChampObjectIndex -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - //Once your application is finished using it, call shutdown() - //to cleanup any loose ends -``` - -#### Persisting a relationship index - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.storeRelationshipIndex(eatsAtTime); //'eatsAtTime' is a reference to a ChampObjectIndex -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - //Once your application is finished using it, call shutdown() - //to cleanup any loose ends -``` -#### Retrieving an object index - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.retrieveObjectIndex("dogName"); -graph.shutdown(); - -``` - -#### Retrieving a relationship index - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.retrieveRelationshipIndex("eatsAtTime"); -graph.shutdown(); - -``` - -### Creating schemas -#### Create a schema - -The following schema restricts objects of type foo to have a required property "property1" as an Integer, and optional property "property2" as a String (Strings are the default type for object properties). It also restricts relationships of type bar to only be allowed to originate from the object type foo. - -``` -ChampSchema.create() - .withObjectConstraint() - .onType("foo") - .withPropertyConstraint() - .onField("property1") - .ofType(Integer.class) - .required() - .build() - .withPropertyConstraint() - .onField("property2") - .optional() - .build() - .build() - .withRelationshipConstraint() - .onType("bar") - .withPropertyConstraint() - .onField("at") - .ofType(String.class) - .optional() - .build() - .withConnectionConstraint() - .sourcedFrom("foo") - .targetToAny() - .build() - .build() - .build(); -``` - -#### Persisting a schema - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); -graph.storeSchema(neighborhoodDogsSchema); //'neighborhoodDogsSchema' is a reference to a ChampObjectIndex -graph.updateSchema(neighborhoodDogConstraint); //'neighborhoosDogConstraint' is a reference to a ChampObjectConstraint -graph.updateSchema(eatsAtConstraint); //'eatsAtConstraint' is a reference to a ChampRelationshipIndex -graph.shutdown(); //The ChampGraph is thread-safe, and only one needs to be created - //Once your application is finished using it, call shutdown() - //to cleanup any loose ends -``` - -#### Retrieving a schema - -``` -final ChampGraph graph = ChampGraph.Factory.newInstance(graphType, "neighborhoodDogsGraph"); - -final ChampSchema schema = graph.retrieveSchema(); - -graph.shutdown(); - -``` - -### Champ Performance Testing - -There is a jar-with-dependencies provided in maven that contains a performance test you can move around and get some idea of how well Champ is running on a cluster of your choice. At the moment, the test only runs against a Titan implementation. - -#### Example running an in-memory test - -``` - -java -cp champ-0.0.1-SNAPSHOT-jar-with-dependencies.jar org.onap.aai.champ.perf.ChampAPIPerformanceTest --champ.graph.type=IN_MEMORY - - -``` - -#### Example running a Titan test - -Note that after the --champ.graph.type=TITAN parameter is provided, you may provide any configuration that is specified by Titan (see link above for the documentation) - -``` - -java -cp champ-0.0.1-SNAPSHOT-jar-with-dependencies.jar org.onap.aai.champ.perf.ChampAPIPerformanceTest --champ.graph.type=TITAN --storage.backend=cassandrathrift --storage.hostname=localhost - - -``` +Creates a new relationship with the specified properties. "source" and "target" must be objects that have already been created, specified by their keys. Returns the created relationship with its key and timestamps. + + URL: https://<host>:9522/services/champ-service/v1/relationships + Method: POST + Content: + { + "type": "testOnTest2", + "properties": { + "beep": "boop", + "a": "b" + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + } + + Response: + Code: 201 Created + Content: + { + "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1", + "type": "testOnTest2", + "properties": { + "beep": "boop", + "a": "b", + "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1" + "aai-last-mod-ts": 1516730919213, + "aai-created-ts": 1516730919213 + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + } + +#### Retrieving relationships +Returns the relationship, looked up by key. + + URL: https://<host>:9522/services/champ-service/v1/relationships/<key> + Method: GET + Response: + Code: 200 OK + Content: + { + "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1", + "type": "testOnTest2", + "properties": { + "beep": "boop", + "a": "b", + "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1" + "aai-last-mod-ts": 1516730919213, + "aai-created-ts": 1516730919213 + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + } + + #### Get relationships for an object + Given an object, returns all connected relationships. + + URL: https://<host>:9522/services/champ-service/v1/objects/relationships/<object-id> + Method: GET + Success Response: + Code: 200 OK + Content: + [ + { + "key": "4ba8dcc2-806d-4312-aecb-503435f355e5", + "type": "testOnTest2", + "properties": { + "beep": "fdsa", + "a": "c", + "aai-uuid": "4ba8dcc2-806d-4312-aecb-503435f355e5" + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + }, + { + "key": "a3096bb8-dc66-4a9c-ab33-a1183f784fbb", + "type": "testOnTest2", + "properties": { + "beep": "fdsa", + "a": "c", + "aai-uuid": "a3096bb8-dc66-4a9c-ab33-a1183f784fbb" + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + } + ] + +#### Updating relationships +Update the relationship properties. Passing timestamps is optional, but the request will be rejected if they are incorrect. + + URL: https://<host>:9522/services/champ-service/v1/relationships/<key> + Method: PUT + Content: + { + "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1", + "type": "testOnTest2", + "properties": { + "beep": "borp", + "a": "c", + "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1" + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + } + + Response: + Code: 200 OK + Content: + { + "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1", + "type": "testOnTest2", + "properties": { + "beep": "borp", + "a": "c", + "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1", + "aai-last-mod-ts": 1516734987294, + "aai-created-ts": 1516730919213 + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + } + +#### Deleting relationships +Deletes the relationship specified by key. + + URL: https://<host>:9522/services/champ-service/v1/relationships/<key> + Method: Delete + Response: 200 OK + +#### Filtered Relationship +Returns a list of relationships that have key/value properties matching the filter + + URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val> + Method: GET + Success Response: + [ + { + "key": "a4d51cd9-f271-4201-975d-168ec6bde501", + "type": "testOnTest2", + "properties": { + "beep": "yes", + "a": "c", + "aai-uuid": "a4d51cd9-f271-4201-975d-168ec6bde501" + }, + "source": { + "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "type": "test", + "properties": { + "key1": "val3", + "key2": "val2", + "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5", + "key4": "val4" + } + }, + "target": { + "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "type": "test2", + "properties": { + "key1": "val1", + "key2": "val2", + "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826", + "key4": "val4" + } + } + } + ] + +### Transactions +Transactions allow multiple graph operations to be grouped into a logical, sandboxed context, so that the option exists to either persist ALL of the grouped changes together, or NONE of them. + +Explicit use of transactions is entirely optional for the client. Calling the API methods described below without supplying a transaction +object results in a transaction being implicitly opened for the single operation, and then automatically committed. + +However, all of the API calls described above related to persisting, retrieving, and deleting vertices, edges and graph partitions also +expose a version of the call which optionally accepts a transaction id (acquired by explicitly calling the /transaction API endpoint). +In this case, the supplied transaction is used for the operation, and no automatic commit occurs. It is the responsibility of +the client to explicitly commit or rollback the transaction at his or her discretion. + +#### Open a new transaction +To use explicit transaction the client must request a transaction id from the Champ service by making a request to open a new transaction. + + URL: https://<host>:9522/services/champ-service/v1/transaction/ + Method: POST + Response: + Code: 200 OK + Content: 5d90f5ae-1f1e-4c3e-b20b-2f7c45f822eb + +#### Working within a transaction +Operations can be done within a transaction by putting the transactionId in the query string. + + Query string: transactionId=<id> + +Example object creation: + + URL: https://<host>:9522/services/champ-service/v1/objects?transactionId=5d90f5ae-1f1e-4c3e-b20b-2f7c45f822eb + +Example relationship update: + + URL: https://<host>:9522/services/champ-service/v1/relationships/<key>?transactionId=5d90f5ae-1f1e-4c3e-b20b-2f7c45f822eb + +#### Checking a transaction +If you wish to check the status of a transaction, you can do a get on it + + URL: https://<host>:9522/services/champ-service/v1/transaction/<transaction-id> + Method: GET +If the transaction is currently open: + + Response: + Code: 200 OK + Content: "fa0890d9-6ac4-40aa-9838-745a25a61fa6 is OPEN" +If the transaction is not open: + + Response: + Code: 404 Not Found + Content: {} + + +#### Committing a transaction +Operations performed within the context of a transaction are not visible outside of that context +until the client explicitly commits the transaction. Up until that point, there is always the +option to just roll back the changes. + + URL: https://<host>:9522/services/champ-service/v1/transaction/<transaction-id> + Method: PUT + Content: {"method":"commit"} + + Response: + Code: 200 OK + Content: COMMITED + +### Rolling back a transaction. +In the event that a sequence of graph operations which were performed within the same transactional context need to be aborted (for example one of the operations in the sequence encountered a failure of some kind) the entire transaction can be aborted by rolling back the transaction. This effectively undoes all of the operations which were performed within the open transaction. + +Note, once a transaction has been committed, it is no longer possible to rollback the contents of the transaction. + + URL: https://<host>:9522/services/champ-service/v1/transaction/<transaction-id> + Method: PUT + Content: {"method":"rollback"} + + Response: + Code: 200 OK + Content: ROLLED BACK diff --git a/License.txt b/champ-lib/License.txt index 469f362..469f362 100644 --- a/License.txt +++ b/champ-lib/License.txt 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/src/main/java/org/onap/aai/champ/ChampAPI.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampAPI.java index 364f8e9..719306f 100644 --- a/src/main/java/org/onap/aai/champ/ChampAPI.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampAPI.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ; +package org.onap.aai.champcore; -import org.onap.aai.champ.graph.impl.ChampAPIImpl; +import org.onap.aai.champcore.graph.impl.ChampAPIImpl; public interface ChampAPI { @@ -33,14 +33,14 @@ public interface ChampAPI { public static final class Factory { private Factory() { throw new RuntimeException("Cannot instantiate ChampAPI.Factory"); } - public static ChampAPI newInstance(ChampGraph.Type type) { + public static ChampAPI newInstance(String type) { return new ChampAPIImpl(type); } } public ChampGraph getGraph(String graphName); - public ChampGraph.Type getType(); + public String getType(); /** * Shutdown the ChampAPI. It is up to the caller to synchronize access to the ChampAPI diff --git a/src/main/java/org/onap/aai/champ/ChampCapabilities.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampCapabilities.java index c7ded86..b0c62cb 100644 --- a/src/main/java/org/onap/aai/champ/ChampCapabilities.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ChampCapabilities.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ; +package org.onap.aai.champcore; public interface ChampCapabilities { 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/src/main/java/org/onap/aai/champ/event/ChampEvent.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/ChampEvent.java index 639a03e..46f1b61 100644 --- a/src/main/java/org/onap/aai/champ/event/ChampEvent.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/event/ChampEvent.java @@ -19,18 +19,19 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.event; +package org.onap.aai.champcore.event; import java.io.IOException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipIndex; +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; @@ -49,11 +50,13 @@ public class ChampEvent { 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() { @@ -76,6 +79,15 @@ public class ChampEvent { this.timestamp = timestamp; } + @JsonProperty("transaction-id") + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + public ChampObject getVertex() { return vertex; } @@ -115,7 +127,15 @@ public class ChampEvent { 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(); @@ -135,6 +155,7 @@ public class ChampEvent { } @Override public String toString() { + return toJson(); } @@ -176,10 +197,16 @@ public class ChampEvent { 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/src/main/java/org/onap/aai/champ/exceptions/ChampIndexNotExistsException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampIndexNotExistsException.java index ae97ea6..e969ce5 100644 --- a/src/main/java/org/onap/aai/champ/exceptions/ChampIndexNotExistsException.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampIndexNotExistsException.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.exceptions; +package org.onap.aai.champcore.exceptions; public final class ChampIndexNotExistsException extends Exception { diff --git a/src/main/java/org/onap/aai/champ/exceptions/ChampMarshallingException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampMarshallingException.java index 2880960..09ede7a 100644 --- a/src/main/java/org/onap/aai/champ/exceptions/ChampMarshallingException.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampMarshallingException.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.exceptions; +package org.onap.aai.champcore.exceptions; public final class ChampMarshallingException extends Exception { diff --git a/src/main/java/org/onap/aai/champ/exceptions/ChampObjectNotExistsException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampObjectNotExistsException.java index 09db181..cd63401 100644 --- a/src/main/java/org/onap/aai/champ/exceptions/ChampObjectNotExistsException.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampObjectNotExistsException.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.exceptions; +package org.onap.aai.champcore.exceptions; public final class ChampObjectNotExistsException extends Exception { diff --git a/src/main/java/org/onap/aai/champ/exceptions/ChampRelationshipNotExistsException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampRelationshipNotExistsException.java index 944ee04..4cdde58 100644 --- a/src/main/java/org/onap/aai/champ/exceptions/ChampRelationshipNotExistsException.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampRelationshipNotExistsException.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.exceptions; +package org.onap.aai.champcore.exceptions; public final class ChampRelationshipNotExistsException extends Exception { diff --git a/src/main/java/org/onap/aai/champ/exceptions/ChampSchemaViolationException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampSchemaViolationException.java index 44df636..b234bc4 100644 --- a/src/main/java/org/onap/aai/champ/exceptions/ChampSchemaViolationException.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampSchemaViolationException.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.exceptions; +package org.onap.aai.champcore.exceptions; public final class ChampSchemaViolationException extends Exception { 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/src/main/java/org/onap/aai/champ/exceptions/ChampUnmarshallingException.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampUnmarshallingException.java index f63d879..b8383d8 100644 --- a/src/main/java/org/onap/aai/champ/exceptions/ChampUnmarshallingException.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/exceptions/ChampUnmarshallingException.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.exceptions; +package org.onap.aai.champcore.exceptions; public final class ChampUnmarshallingException extends Exception { 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/src/main/java/org/onap/aai/champ/graph/impl/ChampAPIImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/ChampAPIImpl.java index ed06429..607ba78 100644 --- a/src/main/java/org/onap/aai/champ/graph/impl/ChampAPIImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/ChampAPIImpl.java @@ -19,14 +19,14 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.graph.impl; +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.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; +import org.onap.aai.champcore.ChampAPI; +import org.onap.aai.champcore.ChampGraph; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,32 +35,33 @@ public class ChampAPIImpl implements ChampAPI { private static final Logger LOGGER = LoggerFactory.getLogger(ChampAPIImpl.class); private final AtomicBoolean shutdown; - private final ChampGraph.Type type; + private final String type; private final ConcurrentHashMap<String, ChampGraph> graphs; - public ChampAPIImpl(ChampGraph.Type type) { + 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; + return graphs; } @Override public ChampGraph getGraph(String graphName) { - if (shutdown.get()) throw new IllegalStateException("Cannot call getGraph() after shutdown() has been initiated"); + if (shutdown.get()) { + throw new IllegalStateException("Cannot call getGraph() after shutdown() has been initiated"); + } - if (getGraphs().containsKey(graphName)) return getGraphs().get(graphName); + if (getGraphs().containsKey(graphName)) { + return getGraphs().get(graphName); + } - final ChampGraph graph = ChampGraph.Factory.newInstance(type, graphName); - - final ChampGraph existingGraph = getGraphs().putIfAbsent(graphName, graph); - - if (existingGraph == null) return graph; - - return existingGraph; + // 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 @@ -80,7 +81,7 @@ public class ChampAPIImpl implements ChampAPI { } @Override - public ChampGraph.Type getType() { + public String getType() { return type; } diff --git a/src/main/java/org/onap/aai/champ/graph/impl/InMemoryChampGraphImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/InMemoryChampGraphImpl.java index 7afb813..5773505 100644 --- a/src/main/java/org/onap/aai/champ/graph/impl/InMemoryChampGraphImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/graph/impl/InMemoryChampGraphImpl.java @@ -19,28 +19,28 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.graph.impl; +package org.onap.aai.champcore.graph.impl; -import java.io.IOException; -import java.util.Collection; 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.champ.ChampCapabilities; -import org.onap.aai.champ.exceptions.ChampIndexNotExistsException; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.ChampRelationshipIndex; -import org.onap.aai.champ.schema.ChampSchemaEnforcer; -import org.onap.aai.champ.schema.DefaultChampSchemaEnforcer; -import org.slf4j.Logger; - -import com.att.nsa.cambria.client.CambriaPublisher; +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 { @@ -73,6 +73,13 @@ public final class InMemoryChampGraphImpl extends AbstractTinkerpopChampGraph { 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(); @@ -84,6 +91,18 @@ public final class InMemoryChampGraphImpl extends AbstractTinkerpopChampGraph { 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); } @@ -98,6 +117,7 @@ public final class InMemoryChampGraphImpl extends AbstractTinkerpopChampGraph { return graph; } + private ConcurrentHashMap<String, ChampObjectIndex> getObjectIndices() { return objectIndices; } @@ -106,7 +126,9 @@ public final class InMemoryChampGraphImpl extends AbstractTinkerpopChampGraph { 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); @@ -179,4 +201,9 @@ public final class InMemoryChampGraphImpl extends AbstractTinkerpopChampGraph { 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/src/main/java/org/onap/aai/champ/ie/Exporter.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Exporter.java index 5c96915..ddea9ec 100644 --- a/src/main/java/org/onap/aai/champ/ie/Exporter.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Exporter.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.ie; +package org.onap.aai.champcore.ie; import java.io.OutputStream; -import org.onap.aai.champ.ChampGraph; +import org.onap.aai.champcore.ChampGraph; public interface Exporter { diff --git a/src/main/java/org/onap/aai/champ/ie/GraphMLImporterExporter.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/GraphMLImporterExporter.java index 4e108e9..71292ce 100644 --- a/src/main/java/org/onap/aai/champ/ie/GraphMLImporterExporter.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/GraphMLImporterExporter.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.ie; +package org.onap.aai.champcore.ie; import java.io.IOException; import java.io.InputStream; @@ -42,16 +42,18 @@ import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.ChampRelationship; +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; @@ -183,25 +185,27 @@ public class GraphMLImporterExporter implements Importer, Exporter { final NodeList data = edge.getChildNodes(); final Object sourceKey = edgeAttributes.getNamedItem("source").getNodeValue(); final Object targetKey = edgeAttributes.getNamedItem("target").getNodeValue(); - final ChampObject sourceObject; - final ChampObject targetObject; - + ChampObject sourceObject=null; + ChampObject targetObject=null; + try { - final Optional<ChampObject> source = graph.queryObjects(Collections.singletonMap("importAssignedId", sourceKey)).findFirst(); - final Optional<ChampObject> target = graph.queryObjects(Collections.singletonMap("importAssignedId", targetKey)).findFirst(); + 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()); + .build(), + Optional.empty()); } else sourceObject = source.get(); if (!target.isPresent()) { targetObject = graph.storeObject(ChampObject.create() .ofType("undefined") .withoutKey() - .build()); + .build(), + Optional.empty()); } else targetObject = target.get(); } catch (ChampMarshallingException e) { @@ -213,6 +217,8 @@ public class GraphMLImporterExporter implements Importer, Exporter { } 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"); @@ -256,7 +262,7 @@ public class GraphMLImporterExporter implements Importer, Exporter { final ChampRelationship relToStore = champRelBuilder.build(); try { - graph.storeRelationship(relToStore); + graph.storeRelationship(relToStore, Optional.empty()); } catch (ChampMarshallingException e) { LOGGER.warn("Failed to marshall ChampObject to backend type", e); } catch (ChampSchemaViolationException e) { @@ -267,7 +273,10 @@ public class GraphMLImporterExporter implements Importer, Exporter { 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) { @@ -323,15 +332,17 @@ public class GraphMLImporterExporter implements Importer, Exporter { final ChampObject objectToStore = champObjBuilder.build(); - try { - graph.storeObject(objectToStore); + 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 @@ -354,7 +365,7 @@ public class GraphMLImporterExporter implements Importer, Exporter { final Map<String, GraphMLKey> edgeKeys = new HashMap<String, GraphMLKey> (); final AtomicInteger elementCount = new AtomicInteger(); - graph.queryObjects(Collections.emptyMap()).forEach(object -> { + graph.queryObjects(Collections.emptyMap(), Optional.empty()).forEach(object -> { nodes.add(object); for (Map.Entry<String, Object> property : object.getProperties().entrySet()) { @@ -366,7 +377,7 @@ public class GraphMLImporterExporter implements Importer, Exporter { nodeKeys.put("type", new GraphMLKey("d" + elementCount.incrementAndGet(), "type", String.class)); }); - graph.queryRelationships(Collections.emptyMap()).forEach(relationship -> { + graph.queryRelationships(Collections.emptyMap(), Optional.empty()).forEach(relationship -> { edges.add(relationship); for (Map.Entry<String, Object> property : relationship.getProperties().entrySet()) { @@ -453,7 +464,7 @@ public class GraphMLImporterExporter implements Importer, Exporter { writer.writeEndElement(); writer.writeEndDocument(); writer.flush(); - } catch (XMLStreamException e) { + } catch (XMLStreamException | ChampTransactionException e) { throw new RuntimeException(e); } } diff --git a/src/main/java/org/onap/aai/champ/ie/Importer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Importer.java index d28da22..4fc22ba 100644 --- a/src/main/java/org/onap/aai/champ/ie/Importer.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/ie/Importer.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.ie; +package org.onap.aai.champcore.ie; import java.io.InputStream; -import org.onap.aai.champ.ChampAPI; +import org.onap.aai.champcore.ChampAPI; public interface Importer { diff --git a/src/main/java/org/onap/aai/champ/model/ChampCardinality.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampCardinality.java index ab8f0a2..b1e72f7 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampCardinality.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampCardinality.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; public enum ChampCardinality { SINGLE, diff --git a/src/main/java/org/onap/aai/champ/model/ChampConnectionConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionConstraint.java index 4e6ff59..af44857 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampConnectionConstraint.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionConstraint.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; diff --git a/src/main/java/org/onap/aai/champ/model/ChampConnectionMultiplicity.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionMultiplicity.java index 1615a5a..d2742fe 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampConnectionMultiplicity.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampConnectionMultiplicity.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; public enum ChampConnectionMultiplicity { NONE, //Cannot have any relationships of a type between two object types diff --git a/src/main/java/org/onap/aai/champ/model/ChampElement.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampElement.java index d92669b..4e938f5 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampElement.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampElement.java @@ -19,7 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; + +import java.util.Map; public interface ChampElement { @@ -28,4 +30,6 @@ public interface ChampElement { public boolean isRelationship(); public ChampRelationship asRelationship(); + + public Map<String, Object> getProperties(); } diff --git a/src/main/java/org/onap/aai/champ/model/ChampField.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampField.java index 1b6ec90..92c3ea0 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampField.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampField.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; 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/src/main/java/org/onap/aai/champ/model/ChampObjectConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectConstraint.java index 0423da4..1a91c7a 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampObjectConstraint.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectConstraint.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; import java.util.HashMap; import java.util.HashSet; diff --git a/src/main/java/org/onap/aai/champ/model/ChampObjectIndex.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectIndex.java index 7d52334..c16844c 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampObjectIndex.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampObjectIndex.java @@ -19,10 +19,10 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; -import org.onap.aai.champ.model.fluent.index.CreateObjectIndexable; -import org.onap.aai.champ.model.fluent.index.impl.CreateObjectIndexableImpl; +import org.onap.aai.champcore.model.fluent.index.CreateObjectIndexable; +import org.onap.aai.champcore.model.fluent.index.impl.CreateObjectIndexableImpl; public final class ChampObjectIndex { diff --git a/src/main/java/org/onap/aai/champ/model/ChampPartition.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPartition.java index 2c5c1a5..0292694 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampPartition.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPartition.java @@ -19,15 +19,15 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +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.champ.model.fluent.partition.CreateChampPartitionable; -import org.onap.aai.champ.model.fluent.partition.impl.CreateChampPartionableImpl; +import org.onap.aai.champcore.model.fluent.partition.CreateChampPartitionable; +import org.onap.aai.champcore.model.fluent.partition.impl.CreateChampPartionableImpl; public final class ChampPartition { @@ -126,7 +126,9 @@ public final class ChampPartition { sb.append(","); } - if (sb.charAt(sb.length() - 1) == ',') sb.deleteCharAt(sb.length() - 1); //Delete last comma + if (sb.charAt(sb.length() - 1) == ',') { + sb.deleteCharAt(sb.length() - 1); //Delete last comma + } sb.append("], relationships: ["); @@ -135,7 +137,9 @@ public final class ChampPartition { sb.append(","); } - if (sb.charAt(sb.length() - 1) == ',') sb.deleteCharAt(sb.length() - 1); //Delete last comma + if (sb.charAt(sb.length() - 1) == ',') { + sb.deleteCharAt(sb.length() - 1); //Delete last comma + } sb.append("]}"); diff --git a/src/main/java/org/onap/aai/champ/model/ChampPropertyConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPropertyConstraint.java index a881cd9..6008d36 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampPropertyConstraint.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampPropertyConstraint.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; diff --git a/src/main/java/org/onap/aai/champ/model/ChampRelationship.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationship.java index 2b4e61b..2d7f033 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampRelationship.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationship.java @@ -19,33 +19,31 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; - -import org.onap.aai.champ.model.fluent.relationship.CreateChampRelationshipable; -import org.onap.aai.champ.model.fluent.relationship.impl.CreateChampRelationshipableImpl; - 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 final String type; //AKA edge label - private final Optional<Object> key; - private final Map<String, Object> properties; - private final ChampObject source; - private final ChampObject target; + 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(); } - private ChampRelationship() { //Not instantiable - throw new RuntimeException("Cannot call ChampRelationship() constructor"); + public ChampRelationship() { //Not instantiable } private ChampRelationship(Builder builder) { @@ -58,12 +56,16 @@ public final class ChampRelationship implements ChampElement { @JsonIgnore public Optional<Object> getKey() { - return key; + if (key == null) { + return Optional.empty (); + } else { + return key; + } } @JsonProperty("key") - public Object getKeyValue() { - return key.orElse(""); + public String getKeyValue() { + return (getKey().isPresent() ? getKey().get() : "").toString(); } public ChampObject getSource() { diff --git a/src/main/java/org/onap/aai/champ/model/ChampRelationshipConstraint.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipConstraint.java index ac030e9..b571205 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampRelationshipConstraint.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipConstraint.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; import java.util.HashMap; import java.util.HashSet; diff --git a/src/main/java/org/onap/aai/champ/model/ChampRelationshipIndex.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipIndex.java index 6b2cee5..03310ba 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampRelationshipIndex.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampRelationshipIndex.java @@ -19,10 +19,10 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; -import org.onap.aai.champ.model.fluent.index.CreateRelationshipIndexable; -import org.onap.aai.champ.model.fluent.index.impl.CreateRelationshipIndexableImpl; +import org.onap.aai.champcore.model.fluent.index.CreateRelationshipIndexable; +import org.onap.aai.champcore.model.fluent.index.impl.CreateRelationshipIndexableImpl; public final class ChampRelationshipIndex { diff --git a/src/main/java/org/onap/aai/champ/model/ChampSchema.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampSchema.java index bd612df..81b97bd 100644 --- a/src/main/java/org/onap/aai/champ/model/ChampSchema.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/ChampSchema.java @@ -19,17 +19,16 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model; +package org.onap.aai.champcore.model; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; - -import org.onap.aai.champ.model.fluent.schema.CreateChampSchemable; -import org.onap.aai.champ.model.fluent.schema.impl.CreateChampSchemableImpl; - 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; diff --git a/src/main/java/org/onap/aai/champ/model/fluent/BuildStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/BuildStep.java index 97f7445..6619b90 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/BuildStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/BuildStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent; +package org.onap.aai.champcore.model.fluent; public interface BuildStep<T> { public T build(); diff --git a/src/main/java/org/onap/aai/champ/model/fluent/KeyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/KeyStep.java index 6b34de1..0be4ac3 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/KeyStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/KeyStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent; +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/src/main/java/org/onap/aai/champ/model/fluent/PropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/PropertiesStep.java index 44b8ada..bac8878 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/PropertiesStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/PropertiesStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent; +package org.onap.aai.champcore.model.fluent; import java.util.Map; diff --git a/src/main/java/org/onap/aai/champ/model/fluent/index/CreateObjectIndexable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateObjectIndexable.java index 57372e5..ccace48 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/CreateObjectIndexable.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateObjectIndexable.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index; +package org.onap.aai.champcore.model.fluent.index; public interface CreateObjectIndexable { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/index/CreateRelationshipIndexable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateRelationshipIndexable.java index 16048ca..e40a86a 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/CreateRelationshipIndexable.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/CreateRelationshipIndexable.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index; +package org.onap.aai.champcore.model.fluent.index; public interface CreateRelationshipIndexable { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/index/ObjectIndexFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexFieldStep.java index 4450e84..869cdd6 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/ObjectIndexFieldStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexFieldStep.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index; +package org.onap.aai.champcore.model.fluent.index; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.fluent.BuildStep; +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/src/main/java/org/onap/aai/champ/model/fluent/index/ObjectIndexTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexTypeStep.java index 71b201f..fc8db8a 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/ObjectIndexTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/ObjectIndexTypeStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index; +package org.onap.aai.champcore.model.fluent.index; public interface ObjectIndexTypeStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/index/RelationshipIndexFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexFieldStep.java index f2bd33f..babd59e 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/RelationshipIndexFieldStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexFieldStep.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index; +package org.onap.aai.champcore.model.fluent.index; -import org.onap.aai.champ.model.ChampRelationshipIndex; -import org.onap.aai.champ.model.fluent.BuildStep; +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/src/main/java/org/onap/aai/champ/model/fluent/index/RelationshipIndexTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexTypeStep.java index add1063..094f872 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/RelationshipIndexTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/RelationshipIndexTypeStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index; +package org.onap.aai.champcore.model.fluent.index; public interface RelationshipIndexTypeStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/index/impl/CreateObjectIndexableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateObjectIndexableImpl.java index f9b58c9..1e0eb1b 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/impl/CreateObjectIndexableImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateObjectIndexableImpl.java @@ -19,15 +19,15 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index.impl; +package org.onap.aai.champcore.model.fluent.index.impl; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.fluent.BuildStep; -import org.onap.aai.champ.model.fluent.index.CreateObjectIndexable; -import org.onap.aai.champ.model.fluent.index.ObjectIndexFieldStep; -import org.onap.aai.champ.model.fluent.index.ObjectIndexTypeStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/index/impl/CreateRelationshipIndexableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateRelationshipIndexableImpl.java index 7c21a62..40d105e 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/index/impl/CreateRelationshipIndexableImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/index/impl/CreateRelationshipIndexableImpl.java @@ -19,14 +19,14 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.index.impl; +package org.onap.aai.champcore.model.fluent.index.impl; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampRelationshipIndex; -import org.onap.aai.champ.model.fluent.BuildStep; -import org.onap.aai.champ.model.fluent.index.CreateRelationshipIndexable; -import org.onap.aai.champ.model.fluent.index.RelationshipIndexFieldStep; -import org.onap.aai.champ.model.fluent.index.RelationshipIndexTypeStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/object/CreateChampObjectable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/CreateChampObjectable.java index 8c586f5..b062a09 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/object/CreateChampObjectable.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/CreateChampObjectable.java @@ -19,10 +19,10 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.object; +package org.onap.aai.champcore.model.fluent.object; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.fluent.KeyStep; +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.fluent.KeyStep; public interface CreateChampObjectable { public KeyStep<ObjectBuildOrPropertiesStep> ofType(String type); diff --git a/src/main/java/org/onap/aai/champ/model/fluent/object/ObjectBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStep.java index 42db899..d982b81 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/object/ObjectBuildOrPropertiesStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStep.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.object; +package org.onap.aai.champcore.model.fluent.object; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.fluent.BuildStep; -import org.onap.aai.champ.model.fluent.PropertiesStep; +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/src/main/java/org/onap/aai/champ/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java index b28045c..7938346 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectBuildOrPropertiesStepImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.object; +package org.onap.aai.champcore.model.fluent.object; import java.util.Map; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObject.Builder; +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampObject.Builder; public final class ObjectBuildOrPropertiesStepImpl implements ObjectBuildOrPropertiesStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/object/ObjectKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectKeyStepImpl.java index f926b66..d05c84d 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/object/ObjectKeyStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/ObjectKeyStepImpl.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.object; +package org.onap.aai.champcore.model.fluent.object; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObject.Builder; -import org.onap.aai.champ.model.fluent.KeyStep; +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> { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/object/impl/CreateChampObjectableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/impl/CreateChampObjectableImpl.java index d6b7e48..242c4c8 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/object/impl/CreateChampObjectableImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/object/impl/CreateChampObjectableImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.object.impl; +package org.onap.aai.champcore.model.fluent.object.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.fluent.KeyStep; -import org.onap.aai.champ.model.fluent.object.CreateChampObjectable; -import org.onap.aai.champ.model.fluent.object.ObjectBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.object.ObjectKeyStepImpl; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/partition/CreateChampPartitionable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/CreateChampPartitionable.java index 785bd88..e65ca4f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/partition/CreateChampPartitionable.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/CreateChampPartitionable.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.partition; +package org.onap.aai.champcore.model.fluent.partition; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.BuildStep; +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> { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/partition/impl/CreateChampPartionableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/impl/CreateChampPartionableImpl.java index f6774fc..cfd284e 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/partition/impl/CreateChampPartionableImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/partition/impl/CreateChampPartionableImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.partition.impl; +package org.onap.aai.champcore.model.fluent.partition.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.partition.CreateChampPartitionable; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/CreateChampRelationshipable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/CreateChampRelationshipable.java index d59a4f0..bb89c21 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/CreateChampRelationshipable.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/CreateChampRelationshipable.java @@ -19,10 +19,10 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.KeyStep; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.aai.champcore.model.fluent.KeyStep; public interface CreateChampRelationshipable { public KeyStep<SourceStep> ofType(String type); diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java index 5c103cd..44ee875 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/RelationshipBuildOrPropertiesStep.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.BuildStep; -import org.onap.aai.champ.model.fluent.PropertiesStep; +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/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceBuildOrPropertiesStep.java index 8650b8a..5e02fa6 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceBuildOrPropertiesStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceBuildOrPropertiesStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface SourceBuildOrPropertiesStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceFromStep.java index d7b2601..18f1da6 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceFromStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceFromStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; -import org.onap.aai.champ.model.ChampObject; +import org.onap.aai.champcore.model.ChampObject; public interface SourceFromStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceKeyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceKeyStep.java index 03991db..8e475e8 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceKeyStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceKeyStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface SourceKeyStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceStep.java index 5b6d737..843cf4f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface SourceStep { public SourceTypeOrFromStep withSource(); diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceTypeOrFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeOrFromStep.java index 932b480..5ae8550 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceTypeOrFromStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeOrFromStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface SourceTypeOrFromStep extends SourceTypeStep, SourceFromStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeStep.java index 1466143..bff8902 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/SourceTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/SourceTypeStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface SourceTypeStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetBuildOrPropertiesStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetBuildOrPropertiesStep.java index a6b5a32..1a8ec49 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetBuildOrPropertiesStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetBuildOrPropertiesStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface TargetBuildOrPropertiesStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetFromStep.java index 5c296d9..cd1551c 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetFromStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetFromStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; -import org.onap.aai.champ.model.ChampObject; +import org.onap.aai.champcore.model.ChampObject; public interface TargetFromStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetKeyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetKeyStep.java index 41e6922..a834edc 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetKeyStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetKeyStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface TargetKeyStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetStep.java index 25d38ed..372d298 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface TargetStep { public TargetTypeOrFromStep withTarget(); diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetTypeOrFromStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeOrFromStep.java index 35a16c3..1631d88 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetTypeOrFromStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeOrFromStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface TargetTypeOrFromStep extends TargetTypeStep, TargetFromStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeStep.java index 6de8915..32f4f3d 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/TargetTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/TargetTypeStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship; +package org.onap.aai.champcore.model.fluent.relationship; public interface TargetTypeStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java index 0a69413..ebc194e 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/ChampRelationshipKeyStepImpl.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.KeyStep; -import org.onap.aai.champ.model.fluent.relationship.SourceStep; +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> { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java index 6125dcd..caf1763 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/CreateChampRelationshipableImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.KeyStep; -import org.onap.aai.champ.model.fluent.relationship.CreateChampRelationshipable; -import org.onap.aai.champ.model.fluent.relationship.RelationshipBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.SourceStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java index bb37e3b..74d0ffb 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/RelationshipBuildOrPropertiesStepImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; import java.util.Map; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.RelationshipBuildOrPropertiesStep; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.aai.champcore.model.fluent.relationship.RelationshipBuildOrPropertiesStep; public final class RelationshipBuildOrPropertiesStepImpl implements RelationshipBuildOrPropertiesStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java index c218472..70d1deb 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceBuildOrPropertiesStepImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.SourceBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.TargetStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceKeyStepImpl.java index 7612b55..d1a6184 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceKeyStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceKeyStepImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampObject.Builder; -import org.onap.aai.champ.model.fluent.relationship.SourceBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.SourceKeyStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceStepImpl.java index cc432d0..492264f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceStepImpl.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.SourceStep; -import org.onap.aai.champ.model.fluent.relationship.SourceTypeOrFromStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java index 9cc0ca2..6ba248f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/SourceTypeOrFromStepImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.SourceBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.SourceKeyStep; -import org.onap.aai.champ.model.fluent.relationship.SourceTypeOrFromStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java index 3b0d7a4..1407703 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetBuildOrPropertiesStepImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.RelationshipBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.TargetBuildOrPropertiesStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetKeyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetKeyStepImpl.java index 5400142..36e49a6 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetKeyStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetKeyStepImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.TargetBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.TargetKeyStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetStepImpl.java index 7b2b582..0721fca 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetStepImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.TargetStep; -import org.onap.aai.champ.model.fluent.relationship.TargetTypeOrFromStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java index 0c813a5..22d1d1d 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/relationship/impl/TargetTypeOrFromStepImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.relationship.impl; +package org.onap.aai.champcore.model.fluent.relationship.impl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.relationship.TargetBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.TargetKeyStep; -import org.onap.aai.champ.model.fluent.relationship.TargetTypeOrFromStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/CreateChampSchemable.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/CreateChampSchemable.java index b0a8a2b..2e1b6d9 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/CreateChampSchemable.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/CreateChampSchemable.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.BuildStep; +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/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintBuildStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintBuildStep.java index 57e677d..57daae8 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintBuildStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintBuildStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.fluent.BuildStep; +import org.onap.aai.champcore.model.fluent.BuildStep; public interface ObjectConstraintBuildStep extends BuildStep<ObjectConstraintPropertyStep> { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldStep.java index d3ac1b5..06fd723 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintFieldStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface ObjectConstraintFieldStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintFieldTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldTypeStep.java index b4831ab..f17608e 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintFieldTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintFieldTypeStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.ChampField; +import org.onap.aai.champcore.model.ChampField; public interface ObjectConstraintFieldTypeStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintPropertyStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintPropertyStep.java index 90a100f..039e4d0 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintPropertyStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintPropertyStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.fluent.BuildStep; +import org.onap.aai.champcore.model.fluent.BuildStep; public interface ObjectConstraintPropertyStep extends BuildStep<CreateChampSchemable> { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java index 1979770..03353b5 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintRequiredOptionalStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.ChampCardinality; +import org.onap.aai.champcore.model.ChampCardinality; public interface ObjectConstraintRequiredOptionalStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintSubStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintSubStep.java index 6fb1266..eb9973f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintSubStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintSubStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface ObjectConstraintSubStep extends ObjectConstraintFieldTypeStep, ObjectConstraintRequiredOptionalStep{ diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintTypeStep.java index 5d8a80b..9ac2f1d 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/ObjectConstraintTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/ObjectConstraintTypeStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +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/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintBuildStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintBuildStep.java index a8a9513..669b829 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintBuildStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintBuildStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.fluent.BuildStep; +import org.onap.aai.champcore.model.fluent.BuildStep; public interface RelationshipConstraintBuildStep extends BuildStep<RelationshipConstraintSubStep> { } diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintFieldStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldStep.java index 3673e3f..17a4bc6 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintFieldStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface RelationshipConstraintFieldStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintFieldTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldTypeStep.java index 59e969e..42b6edf 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintFieldTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintFieldTypeStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.ChampField; +import org.onap.aai.champcore.model.ChampField; public interface RelationshipConstraintFieldTypeStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintMultiplicityStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintMultiplicityStep.java index dd8e76e..9b09a6c 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintMultiplicityStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintMultiplicityStep.java @@ -19,10 +19,10 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.ChampConnectionMultiplicity; -import org.onap.aai.champ.model.fluent.BuildStep; +import org.onap.aai.champcore.model.ChampConnectionMultiplicity; +import org.onap.aai.champcore.model.fluent.BuildStep; public interface RelationshipConstraintMultiplicityStep extends BuildStep<RelationshipConstraintSubStep> { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java index 3d46437..372c53f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintPropertyOptionalsStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface RelationshipConstraintPropertyOptionalsStep extends RelationshipConstraintFieldTypeStep, RelationshipConstraintRequiredOptionalStep { } diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java index 54cf61d..e8fb941 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintRequiredOptionalStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface RelationshipConstraintRequiredOptionalStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintSourceStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSourceStep.java index 53a17bf..0e7f62f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintSourceStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSourceStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface RelationshipConstraintSourceStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintSubStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSubStep.java index 9de5fe7..f27b2a4 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintSubStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintSubStep.java @@ -19,9 +19,9 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; -import org.onap.aai.champ.model.fluent.BuildStep; +import org.onap.aai.champcore.model.fluent.BuildStep; public interface RelationshipConstraintSubStep extends BuildStep<CreateChampSchemable> { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintTargetStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTargetStep.java index 6b86b40..b9ec7a2 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintTargetStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTargetStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface RelationshipConstraintTargetStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintTypeStep.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTypeStep.java index fc20d37..f7a7c3f 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/RelationshipConstraintTypeStep.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/RelationshipConstraintTypeStep.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema; +package org.onap.aai.champcore.model.fluent.schema; public interface RelationshipConstraintTypeStep { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/CreateChampSchemableImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/CreateChampSchemableImpl.java index dd27842..217b55d 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/CreateChampSchemableImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/CreateChampSchemableImpl.java @@ -19,16 +19,16 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; +package org.onap.aai.champcore.model.fluent.schema.impl; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.schema.CreateChampSchemable; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintPropertyStep; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintTypeStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintSubStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintTypeStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java index 7d595a9..8933555 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintBuildStepImpl.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; +package org.onap.aai.champcore.model.fluent.schema.impl; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintBuildStep; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintPropertyStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java index 609f0e3..f149769 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintFieldStepImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; +package org.onap.aai.champcore.model.fluent.schema.impl; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintFieldStep; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintSubStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java index 1e85e8b..c16d311 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintPropertyStepImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; +package org.onap.aai.champcore.model.fluent.schema.impl; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.schema.CreateChampSchemable; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintFieldStep; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintPropertyStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java index 6564cf4..5cb13f3 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/ObjectConstraintSubStepImpl.java @@ -19,17 +19,17 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; - -import org.onap.aai.champ.model.ChampCardinality; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampPropertyConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintBuildStep; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintPropertyStep; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintRequiredOptionalStep; -import org.onap.aai.champ.model.fluent.schema.ObjectConstraintSubStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java index d20d596..906dd4e 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintBuildStepImpl.java @@ -19,13 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; +package org.onap.aai.champcore.model.fluent.schema.impl; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.ChampSchema.Builder; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintBuildStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintSubStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java index 7ef822d..ba39d61 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintPropertyOptionalsStepImpl.java @@ -19,15 +19,15 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; +package org.onap.aai.champcore.model.fluent.schema.impl; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampPropertyConstraint; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintBuildStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintPropertyOptionalsStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintRequiredOptionalStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java index 58db7bb..8a760d1 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintRequiredOptionalStepImpl.java @@ -19,15 +19,15 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; +package org.onap.aai.champcore.model.fluent.schema.impl; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampPropertyConstraint; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.ChampSchema.Builder; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintBuildStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintRequiredOptionalStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java index aca9c0c..6df9cff 100644 --- a/src/main/java/org/onap/aai/champ/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/model/fluent/schema/impl/RelationshipConstraintSubStepImpl.java @@ -19,22 +19,22 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.model.fluent.schema.impl; - -import org.onap.aai.champ.model.ChampConnectionConstraint; -import org.onap.aai.champ.model.ChampConnectionMultiplicity; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.BuildStep; -import org.onap.aai.champ.model.fluent.schema.CreateChampSchemable; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintFieldStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintMultiplicityStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintPropertyOptionalsStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintSourceStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintSubStep; -import org.onap.aai.champ.model.fluent.schema.RelationshipConstraintTargetStep; +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 { diff --git a/src/main/java/org/onap/aai/champ/schema/AlwaysValidChampSchemaEnforcer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/AlwaysValidChampSchemaEnforcer.java index 292ff4c..6aa62a4 100644 --- a/src/main/java/org/onap/aai/champ/schema/AlwaysValidChampSchemaEnforcer.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/AlwaysValidChampSchemaEnforcer.java @@ -19,14 +19,14 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.schema; +package org.onap.aai.champcore.schema; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; +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 { diff --git a/src/main/java/org/onap/aai/champ/schema/ChampSchemaEnforcer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/ChampSchemaEnforcer.java index 978b2a0..5113aa2 100644 --- a/src/main/java/org/onap/aai/champ/schema/ChampSchemaEnforcer.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/ChampSchemaEnforcer.java @@ -19,15 +19,15 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.schema; +package org.onap.aai.champcore.schema; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; +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 { diff --git a/src/main/java/org/onap/aai/champ/schema/DefaultChampSchemaEnforcer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/DefaultChampSchemaEnforcer.java index 8ea93e5..308244e 100644 --- a/src/main/java/org/onap/aai/champ/schema/DefaultChampSchemaEnforcer.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/schema/DefaultChampSchemaEnforcer.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.schema; +package org.onap.aai.champcore.schema; import java.util.HashMap; import java.util.List; @@ -28,16 +28,16 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.model.ChampConnectionConstraint; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampPropertyConstraint; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; +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 { @@ -141,4 +141,4 @@ public final class DefaultChampSchemaEnforcer implements ChampSchemaEnforcer { } } } -} +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/champ/transform/Champformer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/Champformer.java index da2fce7..e07ac14 100644 --- a/src/main/java/org/onap/aai/champ/transform/Champformer.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/Champformer.java @@ -19,11 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.transform; +package org.onap.aai.champcore.transform; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; +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; diff --git a/src/main/java/org/onap/aai/champ/transform/TinkerpopChampformer.java b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/TinkerpopChampformer.java index e24f2dc..8552cc6 100644 --- a/src/main/java/org/onap/aai/champ/transform/TinkerpopChampformer.java +++ b/champ-lib/champ-core/src/main/java/org/onap/aai/champcore/transform/TinkerpopChampformer.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.transform; +package org.onap.aai.champcore.transform; import java.util.Iterator; @@ -27,11 +27,11 @@ 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.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.object.ObjectBuildOrPropertiesStep; -import org.onap.aai.champ.model.fluent.relationship.RelationshipBuildOrPropertiesStep; +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> { 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/src/test/java/org/onap/aai/champ/core/BaseChampAPITest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/BaseChampAPITest.java index af737bc..229e920 100644 --- a/src/test/java/org/onap/aai/champ/core/BaseChampAPITest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/BaseChampAPITest.java @@ -19,32 +19,16 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.core; +package org.onap.aai.champcore.core; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BaseChampAPITest { - private static final Logger LOGGER = LoggerFactory.getLogger(BaseChampAPITest.class); + 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"); - - /* - LOGGER.debug("Cleaning up graph {}", graphName); - - try { - final TitanGraph graph = TitanFactory.build() - .set("storage.backend", "cassandra") - .set("storage.hostname", "localhost") - .set("storage.cassandra.keyspace", graphName) - .open(); - graph.close(); - TitanCleanup.clear(graph); - } catch (IllegalArgumentException e) { - LOGGER.warn("Could not clean up graph - unable to instantiate"); - } - */ } } 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/src/test/java/org/onap/aai/champ/core/ChampElementTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampElementTest.java index af19cc2..9eb5dfe 100644 --- a/src/test/java/org/onap/aai/champ/core/ChampElementTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampElementTest.java @@ -19,14 +19,14 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.core; +package org.onap.aai.champcore.core; import static org.junit.Assert.assertTrue; import org.junit.Test; -import org.onap.aai.champ.model.ChampElement; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; +import org.onap.aai.champcore.model.ChampElement; +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; public class ChampElementTest { diff --git a/src/test/java/org/onap/aai/champ/core/ChampFieldTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampFieldTest.java index 0b4dbb8..4975739 100644 --- a/src/test/java/org/onap/aai/champ/core/ChampFieldTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampFieldTest.java @@ -19,12 +19,12 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.core; +package org.onap.aai.champcore.core; import static org.junit.Assert.assertTrue; import org.junit.Test; -import org.onap.aai.champ.model.ChampField; +import org.onap.aai.champcore.model.ChampField; public class ChampFieldTest { diff --git a/src/test/java/org/onap/aai/champ/core/ChampObjectIndexTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectIndexTest.java index a11b67b..bb2c65e 100644 --- a/src/test/java/org/onap/aai/champ/core/ChampObjectIndexTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampObjectIndexTest.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.core; +package org.onap.aai.champcore.core; import static org.junit.Assert.assertTrue; @@ -29,35 +29,27 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampIndexNotExistsException; -import org.onap.aai.champ.model.ChampObjectIndex; +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 runTest() { - for (ChampGraph.Type apiType : ChampGraph.Type.values()) { + public void runTestMemory() { + runTest("IN_MEMORY"); + } + + public void runTest(String apiType) { final ChampAPI api = ChampAPI.Factory.newInstance(apiType); final String graphName = api.getClass().getSimpleName(); - switch (apiType) { - case IN_MEMORY: - break; - case TITAN: - cleanUp(graphName); - break; - default: - break; - } - ChampObjectIndexTest.testChampObjectIndexCrud(api.getGraph(graphName)); api.shutdown(); - } } - private static void testChampObjectIndexCrud(ChampGraph graph) { + public static void testChampObjectIndexCrud(ChampGraph graph) { final ChampObjectIndex objectIndex = ChampObjectIndex.create() .ofName("fooObjectIndex") 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/src/test/java/org/onap/aai/champ/core/ChampPropertyConstraintTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPropertyConstraintTest.java index 5dfbadf..c82e055 100644 --- a/src/test/java/org/onap/aai/champ/core/ChampPropertyConstraintTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampPropertyConstraintTest.java @@ -19,14 +19,14 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.core; +package org.onap.aai.champcore.core; import static org.junit.Assert.assertTrue; import org.junit.Test; -import org.onap.aai.champ.model.ChampCardinality; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampPropertyConstraint; +import org.onap.aai.champcore.model.ChampCardinality; +import org.onap.aai.champcore.model.ChampField; +import org.onap.aai.champcore.model.ChampPropertyConstraint; public class ChampPropertyConstraintTest { 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/src/test/java/org/onap/aai/champ/core/ChampSchemaTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampSchemaTest.java index df33631..ba62628 100644 --- a/src/test/java/org/onap/aai/champ/core/ChampSchemaTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/core/ChampSchemaTest.java @@ -19,52 +19,47 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.core; +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.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.model.ChampConnectionConstraint; -import org.onap.aai.champ.model.ChampConnectionMultiplicity; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampPropertyConstraint; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.ChampObject.ReservedTypes; -import org.onap.aai.champ.schema.AlwaysValidChampSchemaEnforcer; -import org.onap.aai.champ.schema.ChampSchemaEnforcer; -import org.onap.aai.champ.schema.DefaultChampSchemaEnforcer; +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 runTest() { - for (ChampGraph.Type apiType : ChampGraph.Type.values()) { - final String graphName = ChampSchemaTest.class.getSimpleName(); + public void runInMemoryTest() { + runTest("IN_MEMORY"); + } - switch (apiType) { - case IN_MEMORY: - break; - case TITAN: - cleanUp(graphName); - break; - default: - break; - } + public void runTest(String apiType) { + final String graphName = ChampSchemaTest.class.getSimpleName(); final ChampAPI api = ChampAPI.Factory.newInstance(apiType); @@ -75,7 +70,6 @@ public class ChampSchemaTest extends BaseChampAPITest { } api.shutdown(); - } } public static void testChampSchemaCrud(ChampGraph graph) { @@ -118,14 +112,16 @@ public class ChampSchemaTest extends BaseChampAPITest { .build(); try { - graph.storeObject(emptyFoo); + 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(); @@ -158,16 +154,18 @@ public class ChampSchemaTest extends BaseChampAPITest { ) .build()); - final ChampObject storedEmptyFoo = graph.storeObject(emptyFoo); + final ChampObject storedEmptyFoo = graph.storeObject(emptyFoo, Optional.empty()); - graph.deleteObject(storedEmptyFoo.getKey().get()); + 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())); 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/src/test/java/org/onap/aai/champ/event/AbstractLoggingChampGraphTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/event/AbstractLoggingChampGraphTest.java index 388b16f..1f7451a 100644 --- a/src/test/java/org/onap/aai/champ/event/AbstractLoggingChampGraphTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/event/AbstractLoggingChampGraphTest.java @@ -19,16 +19,13 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.event; +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.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; @@ -37,25 +34,25 @@ import java.util.stream.Stream; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.onap.aai.champ.ChampCapabilities; -import org.onap.aai.champ.event.AbstractLoggingChampGraph; -import org.onap.aai.champ.exceptions.ChampIndexNotExistsException; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampRelationshipIndex; -import org.onap.aai.champ.model.ChampSchema; -import org.slf4j.Logger; +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 com.att.nsa.cambria.client.CambriaPublisher; +import org.onap.aai.event.api.EventPublisher; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; @@ -80,17 +77,20 @@ public class AbstractLoggingChampGraphTest { // Instantiate an 'in-memory' graph for test purposes. Map<String, Object> graphProperties = new HashMap<String, Object>(); - graphProperties.put("champ.event.stream.hosts", "myeventstreamhost"); - graphProperties.put("champ.event.stream.batch-size", 1); - testGraph = new TestGraph(graphProperties, producer); + 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() { + public void tearDown() throws Exception { // Close our stubbed producer and graph. producer.close(); @@ -109,15 +109,69 @@ public class AbstractLoggingChampGraphTest { * @throws JsonParseException * @throws JsonMappingException * @throws IOException + * @throws ChampTransactionException */ @Test - public void vertexOperationsTest() throws ChampMarshallingException, - ChampSchemaViolationException, - ChampObjectNotExistsException, - InterruptedException, - JsonParseException, - JsonMappingException, - IOException { + 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() @@ -127,12 +181,14 @@ public class AbstractLoggingChampGraphTest { .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) @@ -143,6 +199,8 @@ public class AbstractLoggingChampGraphTest { // 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")); @@ -157,7 +215,6 @@ public class AbstractLoggingChampGraphTest { 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 @@ -170,6 +227,7 @@ public class AbstractLoggingChampGraphTest { * @throws JsonParseException * @throws JsonMappingException * @throws IOException + * @throws ChampTransactionException */ @Test public void vertexOperationsWithNullsTest() throws ChampMarshallingException, @@ -178,7 +236,7 @@ public class AbstractLoggingChampGraphTest { InterruptedException, JsonParseException, JsonMappingException, - IOException { + IOException, ChampTransactionException { // Setup our test graph to simulate failures to retrieve data from the graph data store. testGraph.returnNulls(); @@ -190,7 +248,7 @@ public class AbstractLoggingChampGraphTest { .withProperty("p1", "v1") .withProperty("p2", "v2") .build(); - testGraph.storeObject(obj1); + 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); @@ -206,7 +264,7 @@ public class AbstractLoggingChampGraphTest { .build(); // Now, try doing a replace operation. - testGraph.replaceObject(obj2); + 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); @@ -215,7 +273,7 @@ public class AbstractLoggingChampGraphTest { assertNull("Store vertex event should not have been logged to the event stream", loggedEventStr); // Finally, delete the vertex. - testGraph.deleteObject("123"); + 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); @@ -238,6 +296,7 @@ public class AbstractLoggingChampGraphTest { * @throws IOException * @throws ChampUnmarshallingException * @throws ChampRelationshipNotExistsException + * @throws ChampTransactionException */ @Test public void edgeOperationsTest() throws ChampMarshallingException, @@ -248,7 +307,7 @@ public class AbstractLoggingChampGraphTest { JsonMappingException, IOException, ChampUnmarshallingException, - ChampRelationshipNotExistsException { + ChampRelationshipNotExistsException, ChampTransactionException { // Create two vertices to act as the end points of our edge. ChampObject obj1 = ChampObject.create() @@ -269,7 +328,7 @@ public class AbstractLoggingChampGraphTest { .property("property-1", "value-1") .property("property-2", "value-2") .build(); - testGraph.storeRelationship(rel); + 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); @@ -283,7 +342,7 @@ public class AbstractLoggingChampGraphTest { .withKey("123") .withProperty("property-3", "value-3") .build(); - testGraph.replaceRelationship(rel2); + 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); @@ -291,7 +350,7 @@ public class AbstractLoggingChampGraphTest { assertTrue("Entity type for store event was not an edge.", loggedEventStr.contains("relationship")); // Finally, delete our edge. - testGraph.deleteRelationship(rel2); + 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); @@ -314,6 +373,7 @@ public class AbstractLoggingChampGraphTest { * @throws IOException * @throws ChampUnmarshallingException * @throws ChampRelationshipNotExistsException + * @throws ChampTransactionException */ @Test public void edgeOperationsWithNullsTest() throws ChampMarshallingException, @@ -324,7 +384,7 @@ public class AbstractLoggingChampGraphTest { JsonMappingException, IOException, ChampUnmarshallingException, - ChampRelationshipNotExistsException { + ChampRelationshipNotExistsException, ChampTransactionException { // Set up our graph to simulate a failure to retrieve some of the data we need to generate // events. @@ -349,7 +409,7 @@ public class AbstractLoggingChampGraphTest { .property("property-1", "value-1") .property("property-2", "value-2") .build(); - testGraph.storeRelationship(rel); + 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); @@ -364,7 +424,7 @@ public class AbstractLoggingChampGraphTest { .withKey("123") .withProperty("property-3", "value-3") .build(); - testGraph.replaceRelationship(rel2); + 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); @@ -387,6 +447,7 @@ public class AbstractLoggingChampGraphTest { * @throws IOException * @throws ChampUnmarshallingException * @throws ChampRelationshipNotExistsException + * @throws ChampTransactionException */ @Test public void partitionOperationsTest() throws ChampMarshallingException, @@ -397,7 +458,7 @@ public class AbstractLoggingChampGraphTest { JsonMappingException, IOException, ChampUnmarshallingException, - ChampRelationshipNotExistsException { + ChampRelationshipNotExistsException, ChampTransactionException { // Create the vertices and edge objects that we need to create a partition. ChampObject obj1 = ChampObject.create() @@ -425,7 +486,7 @@ public class AbstractLoggingChampGraphTest { .withObject(obj2) .withRelationship(rel) .build(); - testGraph.storePartition(partition); + 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); @@ -433,7 +494,7 @@ public class AbstractLoggingChampGraphTest { assertTrue("Entity type for store event was not a partition.", loggedEventStr.contains("partition")); // Now, delete our partition. - testGraph.deletePartition(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); @@ -456,6 +517,7 @@ public class AbstractLoggingChampGraphTest { * @throws IOException * @throws ChampUnmarshallingException * @throws ChampRelationshipNotExistsException + * @throws ChampTransactionException */ @Test public void partitionOperationsWithNullsTest() throws ChampMarshallingException, @@ -466,7 +528,7 @@ public class AbstractLoggingChampGraphTest { JsonMappingException, IOException, ChampUnmarshallingException, - ChampRelationshipNotExistsException { + ChampRelationshipNotExistsException, ChampTransactionException { // Set up our graph to simulate a failure to retrieve some of the data we need to generate // events. @@ -497,7 +559,7 @@ public class AbstractLoggingChampGraphTest { .withObject(obj2) .withRelationship(rel) .build(); - testGraph.storePartition(partition); + 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); @@ -727,10 +789,8 @@ public class AbstractLoggingChampGraphTest { private boolean returnNulls = false; - protected TestGraph(Map<String, Object> properties, CambriaPublisher producer) { - super(properties); - - setProducer(producer); + protected TestGraph(Map<String, Object> properties) { + super(properties); } public void returnNulls() { @@ -746,9 +806,11 @@ public class AbstractLoggingChampGraphTest { } @Override - public ChampObject executeStoreObject(ChampObject object) throws ChampMarshallingException, - ChampSchemaViolationException, - ChampObjectNotExistsException { + public ChampObject executeStoreObject(ChampObject object, Optional<ChampTransaction> transaction) + throws ChampMarshallingException, + ChampSchemaViolationException, + ChampObjectNotExistsException { + if(!returnNulls) { return object; } else { @@ -757,9 +819,11 @@ public class AbstractLoggingChampGraphTest { } @Override - public ChampObject executeReplaceObject(ChampObject object) throws ChampMarshallingException, - ChampSchemaViolationException, - ChampObjectNotExistsException { + public ChampObject executeReplaceObject(ChampObject object, Optional<ChampTransaction> transaction) + throws ChampMarshallingException, + ChampSchemaViolationException, + ChampObjectNotExistsException { + if(!returnNulls) { return object; } else { @@ -769,6 +833,11 @@ public class AbstractLoggingChampGraphTest { @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() @@ -781,18 +850,24 @@ public class AbstractLoggingChampGraphTest { } @Override - public void executeDeleteObject(Object key) throws ChampObjectNotExistsException { + 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) + public ChampRelationship executeStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampMarshallingException, ChampObjectNotExistsException, @@ -807,7 +882,7 @@ public class AbstractLoggingChampGraphTest { } @Override - public ChampRelationship executeReplaceRelationship(ChampRelationship relationship) + public ChampRelationship executeReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampMarshallingException, ChampSchemaViolationException, @@ -822,18 +897,29 @@ public class AbstractLoggingChampGraphTest { @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) throws ChampRelationshipNotExistsException { + 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; @@ -841,13 +927,18 @@ public class AbstractLoggingChampGraphTest { @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) + public ChampPartition executeStorePartition(ChampPartition partition, Optional<ChampTransaction> transaction) throws ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampMarshallingException, @@ -861,7 +952,7 @@ public class AbstractLoggingChampGraphTest { } @Override - public void executeDeletePartition(ChampPartition graph) { + public void executeDeletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) { // Not used by any tests. } @@ -958,73 +1049,133 @@ public class AbstractLoggingChampGraphTest { // 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 CambriaPublisher { + 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 void logTo(Logger log) { - // Not used by any tests. - } - - @Override - public void setApiCredentials(String apiKey, String apiSecret) { - // Not used by any tests. + 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 void clearApiCredentials() { - // Not used by any tests. + 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 void setHttpBasicCredentials(String username, String password) { - // Not used by any tests. + public int sendSync(String message) throws Exception { + if(!failMode) { + eventStream.add(message); + return 0; + } else { + failedMsgs.add(message); + throw new IOException("nope"); + } } - + @Override - public void clearHttpBasicCredentials() { - // Not used by any tests. + 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 int send(String partition, String msg) throws IOException { - + public void sendAsync(String partitionKey, String message) throws Exception { if(!failMode) { - eventStream.add(msg); - return 0; + eventStream.add(message); } else { - failedMsgs.add(msg); + failedMsgs.add(message); throw new IOException("nope"); - } + } } - @Override - public int send(message msg) throws IOException { - eventStream.add(msg.toString()); - return 0; + 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 int send(Collection<message> msgs) throws IOException { - for(message msg : msgs) { - eventStream.add(msg.toString()); - } - return 0; + public void sendAsync(String message) throws Exception { + if(!failMode) { + eventStream.add(message); + } else { + failedMsgs.add(message); + throw new IOException("nope"); + } } - @Override - public void close() { - // Not used by any tests. - } + 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/src/test/java/org/onap/aai/champ/exceptions/ChampExceptionTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/exceptions/ChampExceptionTest.java index b92ccdf..f7a32f7 100644 --- a/src/test/java/org/onap/aai/champ/exceptions/ChampExceptionTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/exceptions/ChampExceptionTest.java @@ -19,17 +19,11 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.exceptions; +package org.onap.aai.champcore.exceptions; import static org.junit.Assert.assertTrue; import org.junit.Test; -import org.onap.aai.champ.exceptions.ChampIndexNotExistsException; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; public class ChampExceptionTest { diff --git a/src/test/java/org/onap/aai/champ/ie/ExportTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ExportTest.java index 80142b2..bda6122 100644 --- a/src/test/java/org/onap/aai/champ/ie/ExportTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ExportTest.java @@ -19,12 +19,10 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.ie; +package org.onap.aai.champcore.ie; import org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.ie.GraphMLImporterExporter; +import org.onap.aai.champcore.ChampAPI; public class ExportTest { @@ -32,7 +30,7 @@ public class ExportTest { public void testGraphMLExport() { final GraphMLImporterExporter ie = new GraphMLImporterExporter(); - final ChampAPI api = ChampAPI.Factory.newInstance(ChampGraph.Type.IN_MEMORY); + final ChampAPI api = ChampAPI.Factory.newInstance("IN_MEMORY"); ie.importData(api, getClass().getClassLoader().getResourceAsStream("import-test.graphml")); diff --git a/src/test/java/org/onap/aai/champ/ie/ImportTest.java b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ImportTest.java index 0dca95e..67fdb19 100644 --- a/src/test/java/org/onap/aai/champ/ie/ImportTest.java +++ b/champ-lib/champ-core/src/test/java/org/onap/aai/champcore/ie/ImportTest.java @@ -19,7 +19,7 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.ie; +package org.onap.aai.champcore.ie; import static org.junit.Assert.assertTrue; @@ -27,25 +27,25 @@ import java.util.Collections; import java.util.Optional; import org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.ie.GraphMLImporterExporter; +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() { + public void testGraphMLImport() throws ChampTransactionException, AssertionError { final GraphMLImporterExporter importer = new GraphMLImporterExporter(); - final ChampAPI api = ChampAPI.Factory.newInstance(ChampGraph.Type.IN_MEMORY); + 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()).forEach(object -> { + 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"); diff --git a/src/test/resources/import-test.graphml b/champ-lib/champ-core/src/test/resources/import-test.graphml index fd13b6b..fd13b6b 100755..100644 --- a/src/test/resources/import-test.graphml +++ b/champ-lib/champ-core/src/test/resources/import-test.graphml diff --git a/src/test/resources/logback.xml b/champ-lib/champ-core/src/test/resources/logback.xml index 72cd644..72cd644 100644 --- a/src/test/resources/logback.xml +++ b/champ-lib/champ-core/src/test/resources/logback.xml diff --git a/champ-lib/champ-janus/License.txt b/champ-lib/champ-janus/License.txt new file mode 100644 index 0000000..469f362 --- /dev/null +++ b/champ-lib/champ-janus/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-janus/pom.xml b/champ-lib/champ-janus/pom.xml new file mode 100644 index 0000000..15c65e5 --- /dev/null +++ b/champ-lib/champ-janus/pom.xml @@ -0,0 +1,188 @@ +<?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-janus</artifactId> + + <properties> + <tinkerpop.version>3.2.3</tinkerpop.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>tinkergraph-gremlin</artifactId> + <version>${tinkerpop.version}</version> + </dependency> + <dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ-core</artifactId> + <version>1.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ-core</artifactId> + <version>1.2.0-SNAPSHOT</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.janusgraph</groupId> + <artifactId>janusgraph-cassandra</artifactId> + <version>0.1.1</version> + <optional>true</optional> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.janusgraph</groupId> + <artifactId>janusgraph-hbase</artifactId> + <version>0.1.1</version> + <optional>true</optional> + <exclusions> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.7.9</version> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>default-report</id> + <phase>prepare-package</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + <execution> + <id>default-check</id> + <goals> + <goal>check</goal> + </goals> + <configuration> + <rules> + <!-- implementation is needed only for Maven 2 --> + <rule implementation="org.jacoco.maven.RuleConfiguration"> + <element>BUNDLE</element> + <limits> + <!-- implementation is needed only for Maven 2 --> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>INSTRUCTION</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>BRANCH</counter> + <value>COVEREDRATIO</value> + <minimum>.14</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>COMPLEXITY</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>LINE</counter> + <value>COVEREDRATIO</value> + <minimum>.18</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>METHOD</counter> + <value>COVEREDRATIO</value> + <minimum>.10</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>CLASS</counter> + <value>MISSEDCOUNT</value> + <maximum>2</maximum> + </limit> + </limits> + </rule> + </rules> + </configuration> + </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-janus/src/main/java/org/onap/aai/champjanus/graph/impl/GraphSON.java b/champ-lib/champ-janus/src/main/java/org/onap/aai/champjanus/graph/impl/GraphSON.java new file mode 100644 index 0000000..9e849b8 --- /dev/null +++ b/champ-lib/champ-janus/src/main/java/org/onap/aai/champjanus/graph/impl/GraphSON.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champjanus.graph.impl; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +// import com.thinkaurelius.titan.graphdb.tinkerpop.TitanIoRegistry; +import org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper; +import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter; +import org.onap.aai.champcore.FormatMapper; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class GraphSON implements FormatMapper { + private final GraphSONMapper mapper; + private final GraphSONWriter writer; + protected JsonParser parser; + + public GraphSON() { + this.mapper = GraphSONMapper.build().addRegistry(JanusGraphIoRegistry.getInstance ()).create(); + this.writer = GraphSONWriter.build().mapper(this.mapper).create(); + this.parser = new JsonParser(); + } + + public JsonObject formatObject(Object v) { + OutputStream os = new ByteArrayOutputStream(); + String result = ""; + + try { + this.writer.writeVertex(os, (Vertex)v, Direction.BOTH); + result = os.toString(); + } catch (IOException var5) { + var5.printStackTrace(); + } + + return this.parser.parse(result).getAsJsonObject(); + } + + public int parallelThreshold() { + return 50; + } +} diff --git a/champ-lib/champ-janus/src/main/java/org/onap/aai/champjanus/graph/impl/JanusChampGraphImpl.java b/champ-lib/champ-janus/src/main/java/org/onap/aai/champjanus/graph/impl/JanusChampGraphImpl.java new file mode 100644 index 0000000..9ede7df --- /dev/null +++ b/champ-lib/champ-janus/src/main/java/org/onap/aai/champjanus/graph/impl/JanusChampGraphImpl.java @@ -0,0 +1,493 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champjanus.graph.impl; + +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.janusgraph.core.*; +import org.onap.aai.champcore.Formatter; +import org.janusgraph.core.schema.JanusGraphIndex; +import org.janusgraph.core.schema.JanusGraphManagement; +import org.janusgraph.core.schema.SchemaAction; +import org.janusgraph.core.schema.SchemaStatus; +import org.janusgraph.graphdb.database.management.ManagementSystem; +import org.onap.aai.champcore.ChampCapabilities; +import org.onap.aai.champcore.FormatMapper; +import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException; +import org.onap.aai.champcore.exceptions.ChampSchemaViolationException; +import org.onap.aai.champcore.graph.impl.AbstractTinkerpopChampGraph; +import org.onap.aai.champcore.model.*; +import org.onap.aai.champcore.schema.ChampSchemaEnforcer; +import org.onap.aai.champcore.schema.DefaultChampSchemaEnforcer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public final class JanusChampGraphImpl extends AbstractTinkerpopChampGraph { + private static final Logger LOGGER = LoggerFactory.getLogger(JanusChampGraphImpl.class); + private static final String JANUS_CASSANDRA_KEYSPACE = "storage.cassandra.keyspace"; + private static final String JANUS_HBASE_TABLE = "storage.hbase.table"; + private static final String JANUS_UNIQUE_SUFFIX = "graph.unique-instance-id-suffix"; + private static final ChampSchemaEnforcer SCHEMA_ENFORCER = new DefaultChampSchemaEnforcer(); + private static final int REGISTER_OBJECT_INDEX_TIMEOUT_SECS = 30; + + private static final ChampCapabilities CAPABILITIES = new ChampCapabilities() { + + @Override + public boolean canDeleteObjectIndices() { + return false; + } + + @Override + public boolean canDeleteRelationshipIndices() { + return false; + } + }; + + private final JanusGraph graph; + + public JanusChampGraphImpl(Builder builder) { + super(builder.graphConfiguration); + final JanusGraphFactory.Builder janusGraphBuilder = JanusGraphFactory.build(); + + for (Map.Entry<String, Object> janusGraphProperty : builder.graphConfiguration.entrySet()) { + janusGraphBuilder.set(janusGraphProperty.getKey(), janusGraphProperty.getValue()); + } + + janusGraphBuilder.set(JANUS_UNIQUE_SUFFIX, ((short) new Random().nextInt(Short.MAX_VALUE)+"")); + + final Object storageBackend = builder.graphConfiguration.get("storage.backend"); + + if ("cassandra".equals(storageBackend) || + "cassandrathrift".equals(storageBackend) || + "astyanax".equals(storageBackend) || + "embeddedcassandra".equals(storageBackend)) { + + janusGraphBuilder.set(JANUS_CASSANDRA_KEYSPACE, builder.graphName); + } else if ("hbase".equals(storageBackend)) { + janusGraphBuilder.set(JANUS_HBASE_TABLE, builder.graphName); + } else if ("berkleyje".equals(storageBackend)) { + throw new RuntimeException("storage.backend=berkleyje cannot handle multiple graphs on a single DB, not usable"); + } else if ("inmemory".equals(storageBackend)) { + } else { + throw new RuntimeException("Unknown storage.backend=" + storageBackend); + } + + LOGGER.info("Instantiated data access layer for Janus graph data store with backend: " + storageBackend); + this.graph = janusGraphBuilder.open(); + } + + public static class Builder { + private final String graphName; + + private final Map<String, Object> graphConfiguration = new HashMap<String, Object>(); + + public Builder(String graphName) { + this.graphName = graphName; + } + + public Builder(String graphName, Map<String, Object> properties) { + this.graphName = graphName; + properties(properties); + } + + public Builder properties(Map<String, Object> properties) { + if (properties.containsKey(JANUS_CASSANDRA_KEYSPACE)) { + throw new IllegalArgumentException("Cannot use path " + JANUS_CASSANDRA_KEYSPACE + + " in initial configuration - this path is used" + + " to specify graph names"); + } + + this.graphConfiguration.putAll(properties); + return this; + } + + public Builder property(String path, Object value) { + if (path.equals(JANUS_CASSANDRA_KEYSPACE)) { + throw new IllegalArgumentException("Cannot use path " + JANUS_CASSANDRA_KEYSPACE + + " in initial configuration - this path is used" + + " to specify graph names"); + } + graphConfiguration.put(path, value); + return this; + } + + public JanusChampGraphImpl build() { + return new JanusChampGraphImpl(this); + } + } + + @Override + protected JanusGraph getGraph() { + return graph; + } + + + @Override + protected ChampSchemaEnforcer getSchemaEnforcer() { + return SCHEMA_ENFORCER; + } + + @Override + public void executeStoreObjectIndex(ChampObjectIndex index) { + if (isShutdown()) { + throw new IllegalStateException("Cannot call storeObjectIndex() after shutdown has been initiated"); + } + + final JanusGraph graph = getGraph(); + final JanusGraphManagement createIndexMgmt = graph.openManagement(); + final PropertyKey pk = createIndexMgmt.getOrCreatePropertyKey(index.getField().getName()); + + if (createIndexMgmt.getGraphIndex(index.getName()) != null) { + createIndexMgmt.rollback(); + return; //Ignore, index already exists + } + + createIndexMgmt.buildIndex(index.getName(), Vertex.class).addKey(pk).buildCompositeIndex(); + + createIndexMgmt.commit(); + graph.tx().commit(); + + awaitIndexCreation(index.getName()); + } + + @Override + public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName) { + if (isShutdown()) { + throw new IllegalStateException("Cannot call retrieveObjectIndex() after shutdown has been initiated"); + } + + final JanusGraphManagement retrieveIndexMgmt = getGraph().openManagement(); + final JanusGraphIndex index = retrieveIndexMgmt.getGraphIndex(indexName); + + if (index == null) { + return Optional.empty(); + } + if (index.getIndexedElement() != JanusGraphVertex.class) { + return Optional.empty(); + } + + return Optional.of(ChampObjectIndex.create() + .ofName(indexName) + .onType(ChampObject.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build()); + } + + @Override + public Stream<ChampObjectIndex> retrieveObjectIndices() { + if (isShutdown()) { + throw new IllegalStateException("Cannot call retrieveObjectIndices() after shutdown has been initiated"); + } + + final JanusGraphManagement createIndexMgmt = getGraph().openManagement(); + final Iterator<JanusGraphIndex> indices = createIndexMgmt.getGraphIndexes(Vertex.class).iterator(); + + final Iterator<ChampObjectIndex> objIter = new Iterator<ChampObjectIndex>() { + + private ChampObjectIndex next; + + @Override + public boolean hasNext() { + if (indices.hasNext()) { + final JanusGraphIndex index = indices.next(); + + next = ChampObjectIndex.create() + .ofName(index.name()) + .onType(ChampObject.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build(); + return true; + } + + next = null; + return false; + } + + @Override + public ChampObjectIndex next() { + if (next == null) { + throw new NoSuchElementException(); + } + + return next; + } + }; + + return StreamSupport.stream(Spliterators.spliteratorUnknownSize( + objIter, Spliterator.ORDERED | Spliterator.NONNULL), false); + } + + @Override + public void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException { + if (isShutdown()) { + throw new IllegalStateException("Cannot call deleteObjectIndex() after shutdown has been initiated"); + } + + throw new UnsupportedOperationException("Cannot delete indices using the JanusChampImpl"); + } + + @Override + public void executeStoreRelationshipIndex(ChampRelationshipIndex index) { + if (isShutdown()) { + throw new IllegalStateException("Cannot call storeRelationshipIndex() after shutdown has been initiated"); + } + + final JanusGraph graph = getGraph(); + final JanusGraphManagement createIndexMgmt = graph.openManagement(); + final PropertyKey pk = createIndexMgmt.getOrCreatePropertyKey(index.getField().getName()); + + if (createIndexMgmt.getGraphIndex(index.getName()) != null) { + return; //Ignore, index already exists + } + createIndexMgmt.buildIndex(index.getName(), Edge.class).addKey(pk).buildCompositeIndex(); + + createIndexMgmt.commit(); + graph.tx().commit(); + + awaitIndexCreation(index.getName()); + } + + @Override + public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName) { + if (isShutdown()) { + throw new IllegalStateException("Cannot call retrieveRelationshipIndex() after shutdown has been initiated"); + } + + final JanusGraphManagement retrieveIndexMgmt = getGraph().openManagement(); + final JanusGraphIndex index = retrieveIndexMgmt.getGraphIndex(indexName); + + if (index == null) { + return Optional.empty(); + } + if (index.getIndexedElement() != JanusGraphEdge.class) { + return Optional.empty(); + } + + return Optional.of(ChampRelationshipIndex.create() + .ofName(indexName) + .onType(ChampObject.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build()); + } + + @Override + public Stream<ChampRelationshipIndex> retrieveRelationshipIndices() { + if (isShutdown()) { + throw new IllegalStateException("Cannot call retrieveRelationshipIndices() after shutdown has been initiated"); + } + + final JanusGraphManagement createIndexMgmt = getGraph().openManagement(); + final Iterator<JanusGraphIndex> indices = createIndexMgmt.getGraphIndexes(Edge.class).iterator(); + + final Iterator<ChampRelationshipIndex> objIter = new Iterator<ChampRelationshipIndex>() { + + private ChampRelationshipIndex next; + + @Override + public boolean hasNext() { + if (indices.hasNext()) { + final JanusGraphIndex index = indices.next(); + + next = ChampRelationshipIndex.create() + .ofName(index.name()) + .onType(ChampRelationship.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build(); + return true; + } + + next = null; + return false; + } + + @Override + public ChampRelationshipIndex next() { + if (next == null) { + throw new NoSuchElementException(); + } + + return next; + } + }; + + return StreamSupport.stream(Spliterators.spliteratorUnknownSize( + objIter, Spliterator.ORDERED | Spliterator.NONNULL), false); + } + + @Override + public void executeDeleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException { + if (isShutdown()) { + throw new IllegalStateException("Cannot call deleteRelationshipIndex() after shutdown has been initiated"); + } + + throw new UnsupportedOperationException("Cannot delete indices using the JanusChampImpl"); + } + + private Cardinality getJanusCardinality(ChampCardinality cardinality) { + switch (cardinality) { + case LIST: + return Cardinality.LIST; + case SET: + return Cardinality.SET; + case SINGLE: + return Cardinality.SINGLE; + default: + throw new RuntimeException("Unknown ChampCardinality " + cardinality); + } + } + + private void awaitIndexCreation(String indexName) { + //Wait for the index to become available + try { + if (ManagementSystem.awaitGraphIndexStatus(graph, indexName) + .status(SchemaStatus.ENABLED) + .timeout(1, ChronoUnit.SECONDS) + .call() + .getSucceeded()) { + return; //Empty graphs immediately ENABLE indices + } + + if (!ManagementSystem.awaitGraphIndexStatus(graph, indexName) + .status(SchemaStatus.REGISTERED) + .timeout(REGISTER_OBJECT_INDEX_TIMEOUT_SECS, ChronoUnit.SECONDS) + .call() + .getSucceeded()) { + LOGGER.warn("Object index was created, but timed out while waiting for it to be registered"); + return; + } + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while waiting for object index creation status"); + return; + } + + //Reindex the existing data + + try { + final JanusGraphManagement updateIndexMgmt = graph.openManagement(); + updateIndexMgmt.updateIndex(updateIndexMgmt.getGraphIndex(indexName), SchemaAction.REINDEX).get(); + updateIndexMgmt.commit(); + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while reindexing for object index"); + return; + } catch (ExecutionException e) { + LOGGER.warn("Exception occurred during reindexing procedure for creating object index " + indexName, e); + } + + try { + ManagementSystem.awaitGraphIndexStatus(graph, indexName) + .status(SchemaStatus.ENABLED) + .timeout(10, ChronoUnit.MINUTES) + .call(); + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while waiting for index to transition to ENABLED state"); + return; + } + } + + @Override + public ChampCapabilities capabilities() { + return CAPABILITIES; + } + + public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException { + if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated"); + + final ChampSchema currentSchema = retrieveSchema(); + final JanusGraphManagement mgmt = getGraph().openManagement(); + + try { + for (ChampObjectConstraint objConstraint : schema.getObjectConstraints().values()) { + for (ChampPropertyConstraint propConstraint : objConstraint.getPropertyConstraints()) { + final Optional<ChampObjectConstraint> currentObjConstraint = currentSchema.getObjectConstraint(objConstraint.getType()); + + if (currentObjConstraint.isPresent()) { + final Optional<ChampPropertyConstraint> currentPropConstraint = currentObjConstraint.get().getPropertyConstraint(propConstraint.getField().getName()); + + if (currentPropConstraint.isPresent() && currentPropConstraint.get().compareTo(propConstraint) != 0) { + throw new ChampSchemaViolationException("Cannot update already existing property on object type " + objConstraint.getType() + ": " + propConstraint); + } + } + + final String newPropertyKeyName = propConstraint.getField().getName(); + + if (mgmt.getPropertyKey(newPropertyKeyName) != null) continue; //Check Janus to see if another node created this property key + + mgmt.makePropertyKey(newPropertyKeyName) + .dataType(propConstraint.getField().getJavaType()) + .cardinality(getJanusCardinality(propConstraint.getCardinality())) + .make(); + } + } + + for (ChampRelationshipConstraint relConstraint : schema.getRelationshipConstraints().values()) { + + final Optional<ChampRelationshipConstraint> currentRelConstraint = currentSchema.getRelationshipConstraint(relConstraint.getType()); + + for (ChampPropertyConstraint propConstraint : relConstraint.getPropertyConstraints()) { + + if (currentRelConstraint.isPresent()) { + final Optional<ChampPropertyConstraint> currentPropConstraint = currentRelConstraint.get().getPropertyConstraint(propConstraint.getField().getName()); + + if (currentPropConstraint.isPresent() && currentPropConstraint.get().compareTo(propConstraint) != 0) { + throw new ChampSchemaViolationException("Cannot update already existing property on relationship type " + relConstraint.getType()); + } + } + + final String newPropertyKeyName = propConstraint.getField().getName(); + + if (mgmt.getPropertyKey(newPropertyKeyName) != null) continue; //Check Janus to see if another node created this property key + + mgmt.makePropertyKey(newPropertyKeyName) + .dataType(propConstraint.getField().getJavaType()) + .cardinality(getJanusCardinality(propConstraint.getCardinality())) + .make(); + } + + final EdgeLabel edgeLabel = mgmt.getEdgeLabel(relConstraint.getType()); + + if (edgeLabel != null) { + mgmt.makeEdgeLabel(relConstraint.getType()) + .directed() + .make(); + } + } + + mgmt.commit(); + + super.storeSchema(schema); + } catch (SchemaViolationException | ChampSchemaViolationException e) { + mgmt.rollback(); + throw new ChampSchemaViolationException(e); + } + } + + public GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type) { + return query.hasLabel(type); + } +}
\ No newline at end of file diff --git a/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/concurrency/ConcurrencyTest.java b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/concurrency/ConcurrencyTest.java new file mode 100644 index 0000000..68e1a1a --- /dev/null +++ b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/concurrency/ConcurrencyTest.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champjanus.concurrency; + +import org.junit.Test; + +public class ConcurrencyTest { + + @Test + public void runInMemoryConcurrentTest() { + org.onap.aai.champcore.concurrency.ConcurrencyTest baseTest = new org.onap.aai.champcore.concurrency.ConcurrencyTest(); + baseTest.runConcurrentTest("JANUS"); + } +} diff --git a/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampAPITest.java b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampAPITest.java new file mode 100644 index 0000000..4fd9e4a --- /dev/null +++ b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampAPITest.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champjanus.core; + +import org.junit.Test; +import org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl; + +public class ChampAPITest { + @Test + public void testChampGraphInstantiation() throws Exception { + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + + org.onap.aai.champcore.core.ChampAPITest baseTest = new org.onap.aai.champcore.core.ChampAPITest(); + + baseTest.testChampGraphInstantiation(graph); + } +} diff --git a/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampObjectIndexTest.java b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampObjectIndexTest.java new file mode 100644 index 0000000..bd031ef --- /dev/null +++ b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampObjectIndexTest.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champjanus.core; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl; + +public class ChampObjectIndexTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void testChampObjectIndexCrud() throws Exception { + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + + org.onap.aai.champcore.core.ChampObjectIndexTest.testChampObjectIndexCrud(graph); + + graph.shutdown(); + + exception.expect(IllegalStateException.class); + graph.executeDeleteObjectIndex("any"); + } +} diff --git a/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampRelationshipIndexTest.java b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampRelationshipIndexTest.java new file mode 100644 index 0000000..bbfb585 --- /dev/null +++ b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampRelationshipIndexTest.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champjanus.core; + +import org.junit.Test; +import org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl; + +public class ChampRelationshipIndexTest { + @Test + public void testChampRelationshipIndexCrud() { + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + org.onap.aai.champcore.core.ChampRelationshipIndexTest baseTest = new org.onap.aai.champcore.core.ChampRelationshipIndexTest(); + baseTest.testChampRelationshipIndexCrud(graph); + + graph.shutdown(); + } +} diff --git a/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampSchemaTest.java b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampSchemaTest.java new file mode 100644 index 0000000..96ffb25 --- /dev/null +++ b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/ChampSchemaTest.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.champjanus.core; + +import org.junit.Test; +import org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl; + +public class ChampSchemaTest { + @Test + public void testChampSchemaCrud() { + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + org.onap.aai.champcore.core.ChampSchemaTest.testChampSchemaCrud(graph); + + graph.shutdown(); + } +} diff --git a/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/JanusChampSetupTest.java b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/JanusChampSetupTest.java new file mode 100644 index 0000000..3cca54d --- /dev/null +++ b/champ-lib/champ-janus/src/test/java/org/onap/aai/champjanus/core/JanusChampSetupTest.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.champjanus.core; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl; + +import java.util.HashMap; +import java.util.Map; + +public class JanusChampSetupTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void JanusSetupBadBackendTest() { + exception.expect(RuntimeException.class); + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .property("storage.backend", "bad-backend") + .build(); + } + + @Test + public void JanusSetupBerkleyBackendTest() { + exception.expect(RuntimeException.class); + Map<String, Object> propertiesMap = new HashMap<String, Object>(); + propertiesMap.put("storage.backend", "berkleyje"); + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .properties(propertiesMap) + .build(); + } + + @Test + public void JanusSetupBadPropertyTest() { + exception.expect(RuntimeException.class); + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .property("storage.backend", "in-memory") + .property("storage.cassandra.keyspace", "anything") + .build(); + } + + @Test + public void JanusSetupBadPropertiesTest() { + exception.expect(RuntimeException.class); + Map<String, Object> propertiesMap = new HashMap<String, Object>(); + propertiesMap.put("storage.cassandra.keyspace", "anything"); + + JanusChampGraphImpl graph = new JanusChampGraphImpl.Builder("testGraph") + .property("storage.backend", "in-memory") + .properties(propertiesMap) + .build(); + } +} diff --git a/champ-lib/champ-titan/License.txt b/champ-lib/champ-titan/License.txt new file mode 100644 index 0000000..469f362 --- /dev/null +++ b/champ-lib/champ-titan/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-titan/pom.xml b/champ-lib/champ-titan/pom.xml new file mode 100644 index 0000000..72d5039 --- /dev/null +++ b/champ-lib/champ-titan/pom.xml @@ -0,0 +1,188 @@ +<?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-titan</artifactId> + + <properties> + <tinkerpop.version>3.0.1-incubating</tinkerpop.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>tinkergraph-gremlin</artifactId> + <version>${tinkerpop.version}</version> + </dependency> + <dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ-core</artifactId> + <version>1.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ-core</artifactId> + <version>1.2.0-SNAPSHOT</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.thinkaurelius.titan</groupId> + <artifactId>titan-cassandra</artifactId> + <version>1.0.0</version> + <optional>true</optional> + <exclusions> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.thinkaurelius.titan</groupId> + <artifactId>titan-hbase</artifactId> + <version>1.0.0</version> + <optional>true</optional> + <exclusions> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.7.9</version> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>default-report</id> + <phase>prepare-package</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + <execution> + <id>default-check</id> + <goals> + <goal>check</goal> + </goals> + <configuration> + <rules> + <!-- implementation is needed only for Maven 2 --> + <rule implementation="org.jacoco.maven.RuleConfiguration"> + <element>BUNDLE</element> + <limits> + <!-- implementation is needed only for Maven 2 --> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>INSTRUCTION</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>BRANCH</counter> + <value>COVEREDRATIO</value> + <minimum>.14</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>COMPLEXITY</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>LINE</counter> + <value>COVEREDRATIO</value> + <minimum>.18</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>METHOD</counter> + <value>COVEREDRATIO</value> + <minimum>.10</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>CLASS</counter> + <value>MISSEDCOUNT</value> + <maximum>2</maximum> + </limit> + </limits> + </rule> + </rules> + </configuration> + </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-titan/src/main/java/org/onap/aai/champtitan/graph/impl/GraphSON.java b/champ-lib/champ-titan/src/main/java/org/onap/aai/champtitan/graph/impl/GraphSON.java new file mode 100644 index 0000000..e36bd53 --- /dev/null +++ b/champ-lib/champ-titan/src/main/java/org/onap/aai/champtitan/graph/impl/GraphSON.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champtitan.graph.impl; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.thinkaurelius.titan.graphdb.tinkerpop.TitanIoRegistry; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper; +import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter; +import org.onap.aai.champcore.FormatMapper; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class GraphSON implements FormatMapper { + private final GraphSONMapper mapper; + private final GraphSONWriter writer; + protected JsonParser parser; + + public GraphSON() { + this.mapper = GraphSONMapper.build().addRegistry(TitanIoRegistry.INSTANCE).create(); + this.writer = GraphSONWriter.build().mapper(this.mapper).create(); + this.parser = new JsonParser(); + } + + public JsonObject formatObject(Object v) { + OutputStream os = new ByteArrayOutputStream(); + String result = ""; + + try { + this.writer.writeVertex(os, (Vertex)v, Direction.BOTH); + result = os.toString(); + } catch (IOException var5) { + var5.printStackTrace(); + } + + return this.parser.parse(result).getAsJsonObject(); + } + + public int parallelThreshold() { + return 50; + } + +} diff --git a/champ-lib/champ-titan/src/main/java/org/onap/aai/champtitan/graph/impl/TitanChampGraphImpl.java b/champ-lib/champ-titan/src/main/java/org/onap/aai/champtitan/graph/impl/TitanChampGraphImpl.java new file mode 100644 index 0000000..56434be --- /dev/null +++ b/champ-lib/champ-titan/src/main/java/org/onap/aai/champtitan/graph/impl/TitanChampGraphImpl.java @@ -0,0 +1,474 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champtitan.graph.impl; + +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; +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.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.champcore.ChampCapabilities; +import org.onap.aai.champcore.FormatMapper; +import org.onap.aai.champcore.Formatter; +import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException; +import org.onap.aai.champcore.exceptions.ChampSchemaViolationException; +import org.onap.aai.champcore.graph.impl.AbstractTinkerpopChampGraph; +import org.onap.aai.champcore.model.ChampCardinality; +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.ChampPropertyConstraint; +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.champcore.schema.ChampSchemaEnforcer; +import org.onap.aai.champcore.schema.DefaultChampSchemaEnforcer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.thinkaurelius.titan.core.Cardinality; +import com.thinkaurelius.titan.core.EdgeLabel; +import com.thinkaurelius.titan.core.PropertyKey; +import com.thinkaurelius.titan.core.SchemaViolationException; +import com.thinkaurelius.titan.core.TitanEdge; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanVertex; +import com.thinkaurelius.titan.core.schema.SchemaAction; +import com.thinkaurelius.titan.core.schema.SchemaStatus; +import com.thinkaurelius.titan.core.schema.TitanGraphIndex; +import com.thinkaurelius.titan.core.schema.TitanManagement; +import com.thinkaurelius.titan.graphdb.database.management.ManagementSystem; + +public final class TitanChampGraphImpl extends AbstractTinkerpopChampGraph { + + private static final Logger LOGGER = LoggerFactory.getLogger(TitanChampGraphImpl.class); + private static final String TITAN_UNIQUE_SUFFIX = "graph.unique-instance-id-suffix"; + private static final String TITAN_CASSANDRA_KEYSPACE = "storage.cassandra.keyspace"; + private static final String TITAN_HBASE_TABLE = "storage.hbase.table"; + private static final ChampSchemaEnforcer SCHEMA_ENFORCER = new DefaultChampSchemaEnforcer(); + private static final int REGISTER_OBJECT_INDEX_TIMEOUT_SECS = 30; + + private static final ChampCapabilities CAPABILITIES = new ChampCapabilities() { + + @Override + public boolean canDeleteObjectIndices() { + return false; + } + + @Override + public boolean canDeleteRelationshipIndices() { + return false; + } + }; + + private final TitanGraph graph; + + public TitanChampGraphImpl(Builder builder) { + super(builder.graphConfiguration); + final TitanFactory.Builder titanGraphBuilder = TitanFactory.build(); + + for (Entry<String, Object> titanGraphProperty : builder.graphConfiguration.entrySet()) { + titanGraphBuilder.set(titanGraphProperty.getKey(), titanGraphProperty.getValue()); + } + + titanGraphBuilder.set(TITAN_UNIQUE_SUFFIX, ((short) new Random().nextInt(Short.MAX_VALUE)+"")); + + final Object storageBackend = builder.graphConfiguration.get("storage.backend"); + + if ("cassandra".equals(storageBackend) || + "cassandrathrift".equals(storageBackend) || + "astyanax".equals(storageBackend) || + "embeddedcassandra".equals(storageBackend)) { + titanGraphBuilder.set(TITAN_CASSANDRA_KEYSPACE, builder.graphName); + } else if ("hbase".equals(storageBackend)) { + titanGraphBuilder.set(TITAN_HBASE_TABLE, builder.graphName); + } else if ("berkleyje".equals(storageBackend)) { + throw new RuntimeException("storage.backend=berkleyje cannot handle multiple graphs on a single DB, not usable"); + } else if ("inmemory".equals(storageBackend)) { + } else { + throw new RuntimeException("Unknown storage.backend=" + storageBackend); + } + + LOGGER.info("Instantiated data access layer for Titan graph data store with backend: " + storageBackend); + + this.graph = titanGraphBuilder.open(); + } + + public static class Builder { + private final String graphName; + + private final Map<String, Object> graphConfiguration = new HashMap<String, Object> (); + + public Builder(String graphName) { + this.graphName = graphName; + } + + public Builder(String graphName, Map<String, Object> properties) { + this.graphName = graphName; + properties(properties); + } + + public Builder properties(Map<String, Object> properties) { + if (properties.containsKey(TITAN_CASSANDRA_KEYSPACE)) + throw new IllegalArgumentException("Cannot use path " + TITAN_CASSANDRA_KEYSPACE + + " in initial configuration - this path is used" + + " to specify graph names"); + + this.graphConfiguration.putAll(properties); + return this; + } + + public Builder property(String path, Object value) { + if (path.equals(TITAN_CASSANDRA_KEYSPACE)) + throw new IllegalArgumentException("Cannot use path " + TITAN_CASSANDRA_KEYSPACE + + " in initial configuration - this path is used" + + " to specify graph names"); + graphConfiguration.put(path, value); + return this; + } + + public TitanChampGraphImpl build() { + return new TitanChampGraphImpl(this); + } + } + + @Override + protected TitanGraph getGraph() { + return graph; + } + + @Override + protected ChampSchemaEnforcer getSchemaEnforcer() { + return SCHEMA_ENFORCER; + } + + public void executeStoreObjectIndex(ChampObjectIndex index) { + if (isShutdown()) throw new IllegalStateException("Cannot call storeObjectIndex() after shutdown has been initiated"); + + final TitanGraph graph = getGraph(); + final TitanManagement createIndexMgmt = graph.openManagement(); + final PropertyKey pk = createIndexMgmt.getOrCreatePropertyKey(index.getField().getName()); + + if (createIndexMgmt.getGraphIndex(index.getName()) != null) { + createIndexMgmt.rollback(); + return; //Ignore, index already exists + } + + createIndexMgmt.buildIndex(index.getName(), Vertex.class).addKey(pk).buildCompositeIndex(); + + createIndexMgmt.commit(); + graph.tx().commit(); + + awaitIndexCreation(index.getName()); + } + + @Override + public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName) { + if (isShutdown()) throw new IllegalStateException("Cannot call retrieveObjectIndex() after shutdown has been initiated"); + + final TitanManagement retrieveIndexMgmt = getGraph().openManagement(); + final TitanGraphIndex index = retrieveIndexMgmt.getGraphIndex(indexName); + + if (index == null) return Optional.empty(); + if (index.getIndexedElement() != TitanVertex.class) return Optional.empty(); + + return Optional.of(ChampObjectIndex.create() + .ofName(indexName) + .onType(ChampObject.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build()); + } + + @Override + public Stream<ChampObjectIndex> retrieveObjectIndices() { + if (isShutdown()) throw new IllegalStateException("Cannot call retrieveObjectIndices() after shutdown has been initiated"); + + final TitanManagement createIndexMgmt = getGraph().openManagement(); + final Iterator<TitanGraphIndex> indices = createIndexMgmt.getGraphIndexes(Vertex.class).iterator(); + + final Iterator<ChampObjectIndex> objIter = new Iterator<ChampObjectIndex> () { + + private ChampObjectIndex next; + + @Override + public boolean hasNext() { + if (indices.hasNext()) { + final TitanGraphIndex index = indices.next(); + + next = ChampObjectIndex.create() + .ofName(index.name()) + .onType(ChampObject.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build(); + return true; + } + + next = null; + return false; + } + + @Override + public ChampObjectIndex next() { + if (next == null) throw new NoSuchElementException(); + + return next; + } + }; + + return StreamSupport.stream(Spliterators.spliteratorUnknownSize( + objIter, Spliterator.ORDERED | Spliterator.NONNULL), false); + } + + public void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException { + if (isShutdown()) throw new IllegalStateException("Cannot call deleteObjectIndex() after shutdown has been initiated"); + + throw new UnsupportedOperationException("Cannot delete indices using the TitanChampImpl"); + } + + public void executeStoreRelationshipIndex(ChampRelationshipIndex index) { + if (isShutdown()) throw new IllegalStateException("Cannot call storeRelationshipIndex() after shutdown has been initiated"); + + final TitanGraph graph = getGraph(); + final TitanManagement createIndexMgmt = graph.openManagement(); + final PropertyKey pk = createIndexMgmt.getOrCreatePropertyKey(index.getField().getName()); + + if (createIndexMgmt.getGraphIndex(index.getName()) != null) return; //Ignore, index already exists + createIndexMgmt.buildIndex(index.getName(), Edge.class).addKey(pk).buildCompositeIndex(); + + createIndexMgmt.commit(); + graph.tx().commit(); + + awaitIndexCreation(index.getName()); + } + + @Override + public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName) { + if (isShutdown()) throw new IllegalStateException("Cannot call retrieveRelationshipIndex() after shutdown has been initiated"); + + final TitanManagement retrieveIndexMgmt = getGraph().openManagement(); + final TitanGraphIndex index = retrieveIndexMgmt.getGraphIndex(indexName); + + if (index == null) return Optional.empty(); + if (index.getIndexedElement() != TitanEdge.class) return Optional.empty(); + + return Optional.of(ChampRelationshipIndex.create() + .ofName(indexName) + .onType(ChampObject.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build()); + } + + @Override + public Stream<ChampRelationshipIndex> retrieveRelationshipIndices() { + if (isShutdown()) throw new IllegalStateException("Cannot call retrieveRelationshipIndices() after shutdown has been initiated"); + + final TitanManagement createIndexMgmt = getGraph().openManagement(); + final Iterator<TitanGraphIndex> indices = createIndexMgmt.getGraphIndexes(Edge.class).iterator(); + + final Iterator<ChampRelationshipIndex> objIter = new Iterator<ChampRelationshipIndex> () { + + private ChampRelationshipIndex next; + + @Override + public boolean hasNext() { + if (indices.hasNext()) { + final TitanGraphIndex index = indices.next(); + + next = ChampRelationshipIndex.create() + .ofName(index.name()) + .onType(ChampRelationship.ReservedTypes.ANY.toString()) + .forField(index.getFieldKeys()[0].name()) + .build(); + return true; + } + + next = null; + return false; + } + + @Override + public ChampRelationshipIndex next() { + if (next == null) throw new NoSuchElementException(); + + return next; + } + }; + + return StreamSupport.stream(Spliterators.spliteratorUnknownSize( + objIter, Spliterator.ORDERED | Spliterator.NONNULL), false); + } + + public void executeDeleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException { + if (isShutdown()) throw new IllegalStateException("Cannot call deleteRelationshipIndex() after shutdown has been initiated"); + + throw new UnsupportedOperationException("Cannot delete indices using the TitanChampImpl"); + } + + private Cardinality getTitanCardinality(ChampCardinality cardinality) { + switch (cardinality) { + case LIST: + return Cardinality.LIST; + case SET: + return Cardinality.SET; + case SINGLE: + return Cardinality.SINGLE; + default: + throw new RuntimeException("Unknown ChampCardinality " + cardinality); + } + } + + private void awaitIndexCreation(String indexName) { + //Wait for the index to become available + try { + if (ManagementSystem.awaitGraphIndexStatus(graph, indexName) + .status(SchemaStatus.ENABLED) + .timeout(1, ChronoUnit.SECONDS) + .call() + .getSucceeded()) { + return; //Empty graphs immediately ENABLE indices + } + + if (!ManagementSystem.awaitGraphIndexStatus(graph, indexName) + .status(SchemaStatus.REGISTERED) + .timeout(REGISTER_OBJECT_INDEX_TIMEOUT_SECS, ChronoUnit.SECONDS) + .call() + .getSucceeded()) { + LOGGER.warn("Object index was created, but timed out while waiting for it to be registered"); + return; + } + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while waiting for object index creation status"); + return; + } + + //Reindex the existing data + + try { + final TitanManagement updateIndexMgmt = graph.openManagement(); + updateIndexMgmt.updateIndex(updateIndexMgmt.getGraphIndex(indexName),SchemaAction.REINDEX).get(); + updateIndexMgmt.commit(); + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while reindexing for object index"); + return; + } catch (ExecutionException e) { + LOGGER.warn("Exception occurred during reindexing procedure for creating object index " + indexName, e); + } + + try { + ManagementSystem.awaitGraphIndexStatus(graph, indexName) + .status(SchemaStatus.ENABLED) + .timeout(10, ChronoUnit.MINUTES) + .call(); + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while waiting for index to transition to ENABLED state"); + return; + } + } + + @Override + public ChampCapabilities capabilities() { + return CAPABILITIES; + } + + @Override + public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException { + if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated"); + + final ChampSchema currentSchema = retrieveSchema(); + final TitanManagement mgmt = getGraph().openManagement(); + + try { + for (ChampObjectConstraint objConstraint : schema.getObjectConstraints().values()) { + for (ChampPropertyConstraint propConstraint : objConstraint.getPropertyConstraints()) { + final Optional<ChampObjectConstraint> currentObjConstraint = currentSchema.getObjectConstraint(objConstraint.getType()); + + if (currentObjConstraint.isPresent()) { + final Optional<ChampPropertyConstraint> currentPropConstraint = currentObjConstraint.get().getPropertyConstraint(propConstraint.getField().getName()); + + if (currentPropConstraint.isPresent() && currentPropConstraint.get().compareTo(propConstraint) != 0) { + throw new ChampSchemaViolationException("Cannot update already existing property on object type " + objConstraint.getType() + ": " + propConstraint); + } + } + + final String newPropertyKeyName = propConstraint.getField().getName(); + + if (mgmt.getPropertyKey(newPropertyKeyName) != null) continue; //Check Titan to see if another node created this property key + + mgmt.makePropertyKey(newPropertyKeyName) + .dataType(propConstraint.getField().getJavaType()) + .cardinality(getTitanCardinality(propConstraint.getCardinality())) + .make(); + } + } + + for (ChampRelationshipConstraint relConstraint : schema.getRelationshipConstraints().values()) { + + final Optional<ChampRelationshipConstraint> currentRelConstraint = currentSchema.getRelationshipConstraint(relConstraint.getType()); + + for (ChampPropertyConstraint propConstraint : relConstraint.getPropertyConstraints()) { + + if (currentRelConstraint.isPresent()) { + final Optional<ChampPropertyConstraint> currentPropConstraint = currentRelConstraint.get().getPropertyConstraint(propConstraint.getField().getName()); + + if (currentPropConstraint.isPresent() && currentPropConstraint.get().compareTo(propConstraint) != 0) { + throw new ChampSchemaViolationException("Cannot update already existing property on relationship type " + relConstraint.getType()); + } + } + + final String newPropertyKeyName = propConstraint.getField().getName(); + + if (mgmt.getPropertyKey(newPropertyKeyName) != null) continue; //Check Titan to see if another node created this property key + + mgmt.makePropertyKey(newPropertyKeyName) + .dataType(propConstraint.getField().getJavaType()) + .cardinality(getTitanCardinality(propConstraint.getCardinality())) + .make(); + } + + final EdgeLabel edgeLabel = mgmt.getEdgeLabel(relConstraint.getType()); + + if (edgeLabel != null) mgmt.makeEdgeLabel(relConstraint.getType()) + .directed() + .make(); + } + + mgmt.commit(); + + super.storeSchema(schema); + } catch (SchemaViolationException | ChampSchemaViolationException e) { + mgmt.rollback(); + throw new ChampSchemaViolationException(e); + } + } + + @Override + public GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type) { + return query.hasLabel((String) type); + } +} diff --git a/src/main/java/org/onap/aai/champ/perf/ChampAPIPerformanceTest.java b/champ-lib/champ-titan/src/main/java/org/onap/aai/champtitan/perf/ChampAPIPerformanceTest.java index e1266aa..37ea4ff 100644 --- a/src/main/java/org/onap/aai/champ/perf/ChampAPIPerformanceTest.java +++ b/champ-lib/champ-titan/src/main/java/org/onap/aai/champtitan/perf/ChampAPIPerformanceTest.java @@ -19,40 +19,27 @@ * ============LICENSE_END============================================ * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ -package org.onap.aai.champ.perf; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.graph.impl.InMemoryChampGraphImpl; -import org.onap.aai.champ.graph.impl.TitanChampGraphImpl; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipIndex; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.schema.ChampSchemaEnforcer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +package org.onap.aai.champtitan.perf; import com.thinkaurelius.titan.core.TitanFactory; import com.thinkaurelius.titan.core.TitanFactory.Builder; import com.thinkaurelius.titan.core.TitanGraph; import com.thinkaurelius.titan.core.util.TitanCleanup; +import org.onap.aai.champcore.ChampGraph; +import org.onap.aai.champcore.exceptions.*; +import org.onap.aai.champcore.graph.impl.InMemoryChampGraphImpl; +import org.onap.aai.champcore.model.*; +import org.onap.aai.champcore.schema.ChampSchemaEnforcer; +import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class ChampAPIPerformanceTest { private static final Logger LOGGER = LoggerFactory.getLogger(ChampAPIPerformanceTest.class); @@ -97,43 +84,51 @@ public class ChampAPIPerformanceTest { public static void main(String[] args) { - if (args.length < 1 || !args[0].startsWith("--champ.graph.type=")) { - throw new RuntimeException("Must provide --champ.graph.type=" + ChampGraph.Type.values() + " as first parameter"); + if (args.length < 1 || !args[0].startsWith("--champcore.graph.type=")) { + throw new RuntimeException("Must provide --champcore.graph.type=" + " as first parameter"); } - final ChampGraph.Type graphType = ChampGraph.Type.valueOf(args[0].split("=")[1]); + final String graphType = args[0].split("=")[1]; final Map<String, String> settings = new HashMap<String, String> (); for (int i = 1; i < args.length; i++) { - if (!args[i].startsWith("--")) throw new RuntimeException("Bad command line argument: " + args[i]); + if (!args[i].startsWith("--")) { + throw new RuntimeException("Bad command line argument: " + args[i]); + } final String[] keyValue = args[i].replaceFirst("--", "").split("="); - if (keyValue.length != 2) throw new RuntimeException("Bad command line argument: " + args[i]); + if (keyValue.length != 2) { + throw new RuntimeException("Bad command line argument: " + args[i]); + } settings.put(keyValue[0], keyValue[1]); } LOGGER.info("Provided graph settings: " + settings); - if (graphType == ChampGraph.Type.TITAN) cleanUp(getGraphName(), settings); + if (graphType.equals("TITAN")) { + cleanUp(getGraphName(), settings); + } LOGGER.info("Graph cleaned, instantiating ChampGraph"); final ChampGraph graph; switch (graphType) { - case IN_MEMORY: + case "IN_MEMORY": final InMemoryChampGraphImpl.Builder inMemGraphBuilder = new InMemoryChampGraphImpl.Builder(); - if (settings.containsKey("champ.schema.enforcer")) { - final String schemaEnforcerClassStr = settings.get("champ.schema.enforcer"); + if (settings.containsKey("champcore.schema.enforcer")) { + final String schemaEnforcerClassStr = settings.get("champcore.schema.enforcer"); try { final Class<?> schemaEnforcer = Class.forName(schemaEnforcerClassStr); - if (!schemaEnforcer.isAssignableFrom(ChampSchemaEnforcer.class)) throw new RuntimeException("Unknown ChampSchemaEnforcer " + schemaEnforcer); + if (!schemaEnforcer.isAssignableFrom(ChampSchemaEnforcer.class)) { + throw new RuntimeException("Unknown ChampSchemaEnforcer " + schemaEnforcer); + } inMemGraphBuilder.schemaEnforcer((ChampSchemaEnforcer) schemaEnforcer.newInstance()); } catch (ClassNotFoundException e) { @@ -147,7 +142,7 @@ public class ChampAPIPerformanceTest { graph = inMemGraphBuilder.build(); break; - case TITAN: + case "TITAN": final TitanChampGraphImpl.Builder graphBuilder = new TitanChampGraphImpl.Builder(getGraphName()); for (Entry<String, String> setting : settings.entrySet()) { @@ -160,10 +155,14 @@ public class ChampAPIPerformanceTest { throw new RuntimeException("Unknown ChampGraph.Type " + graphType); } - if (graph.queryObjects(Collections.emptyMap()).limit(1).count() > 0) { - graph.shutdown(); - throw new RuntimeException("Expected empty graph"); - } + try { + if (graph.queryObjects(Collections.emptyMap(), Optional.empty()).limit(1).count() > 0) { + graph.shutdown(); + throw new RuntimeException("Expected empty graph"); + } + } catch (ChampTransactionException e) { + throw new RuntimeException("Transaction failure"); + } LOGGER.info("Graph instantiated, warming up JVM"); warmUp(graph); @@ -203,22 +202,22 @@ public class ChampAPIPerformanceTest { private static void storeSchema(ChampGraph graph, boolean warmUp) { try { graph.storeSchema( - ChampSchema.create() + ChampSchema.create() .withObjectConstraint() - .onType("foo") - .withPropertyConstraint() - .onField("fooObjectNumber") - .optional() - .build() - .build() + .onType("foo") + .withPropertyConstraint() + .onField("fooObjectNumber") + .optional() + .build() + .build() .withRelationshipConstraint() - .onType("bar") - .withPropertyConstraint() - .onField("barObjectNumber") - .ofType(ChampField.Type.INTEGER) - .optional() - .build() - .build() + .onType("bar") + .withPropertyConstraint() + .onField("barObjectNumber") + .ofType(ChampField.Type.INTEGER) + .optional() + .build() + .build() .build() ); } catch (ChampSchemaViolationException e) { @@ -258,7 +257,13 @@ public class ChampAPIPerformanceTest { for (int i = 0; i < NUM_RELATIONSHIPS; i++) { final long startTime = System.nanoTime(); - final Stream<ChampRelationship> objects = graph.queryRelationships(Collections.singletonMap("relationshipNumber", i)); + Stream<ChampRelationship> objects; + try { + objects = graph.queryRelationships(Collections.singletonMap("relationshipNumber", i), Optional.empty()); + } catch (ChampTransactionException e) { + throw new RuntimeException(e); + } + objects.findFirst().get(); final double elapsedMs = (System.nanoTime() - startTime) / 1000.0 / 1000.0; latencies[i] = elapsedMs; @@ -285,7 +290,12 @@ public class ChampAPIPerformanceTest { for (int i = 0; i < NUM_OBJECTS; i++) { final long startTime = System.nanoTime(); - final Stream<ChampObject> objects = graph.queryObjects(Collections.singletonMap("objectNumber", i)); + Stream<ChampObject> objects; + try { + objects = graph.queryObjects(Collections.singletonMap("objectNumber", i), Optional.empty()); + } catch (ChampTransactionException e) { + throw new RuntimeException(e); + } objects.findFirst().get(); @@ -311,32 +321,46 @@ public class ChampAPIPerformanceTest { private static List<ChampObject> retrieveBulkObjects(ChampGraph graph, boolean warmUp) { final long startTime = System.nanoTime(); - final Stream<ChampObject> objects = graph.queryObjects( - Collections.singletonMap( - ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString(), "foo" - ) - ); + Stream<ChampObject> objects; + try { + objects = graph.queryObjects( + Collections.singletonMap( + ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString(), "foo" + ), Optional.empty() + ); + } catch (ChampTransactionException e) { + throw new RuntimeException(e); + } final List<ChampObject> objectsAsList = objects.collect(Collectors.toList()); final double elapsedSecs = (System.nanoTime() - startTime) / 1000.0 / 1000.0 / 1000.0; - if (!warmUp) LOGGER.info("Bulk read " + objectsAsList.size() + " objects in " + elapsedSecs + "s (" + objectsAsList.size() / elapsedSecs + " objects/s)"); + if (!warmUp) { + LOGGER.info("Bulk read " + objectsAsList.size() + " objects in " + elapsedSecs + "s (" + objectsAsList.size() / elapsedSecs + " objects/s)"); + } return objectsAsList; } private static List<ChampRelationship> retrieveBulkRelationships(ChampGraph graph, boolean warmUp) { final long startTime = System.nanoTime(); - final Stream<ChampRelationship> relationships = graph.queryRelationships( - Collections.singletonMap( - ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString(), "bazz" - ) - ); + Stream<ChampRelationship> relationships; + try { + relationships = graph.queryRelationships( + Collections.singletonMap( + ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString(), "bazz" + ), Optional.empty() + ); + } catch (ChampTransactionException e) { + throw new RuntimeException(e); + } final List<ChampRelationship> relationshipsAsList = relationships.collect(Collectors.toList()); final double elapsedSecs = (System.nanoTime() - startTime) / 1000.0 / 1000.0 / 1000.0; - if (!warmUp) LOGGER.info("Bulk read " + relationshipsAsList.size() + " relationships in " + elapsedSecs + "s (" + relationshipsAsList.size() / elapsedSecs + " relationships/s)"); + if (!warmUp) { + LOGGER.info("Bulk read " + relationshipsAsList.size() + " relationships in " + elapsedSecs + "s (" + relationshipsAsList.size() / elapsedSecs + " relationships/s)"); + } return relationshipsAsList; } @@ -354,7 +378,7 @@ public class ChampAPIPerformanceTest { .ofType("foo") .withoutKey() .withProperty("objectNumber", i) - .build() + .build(), Optional.empty() ); final double elapsedMs = (System.nanoTime() - startTime) / 1000.0 / 1000.0; @@ -365,7 +389,9 @@ public class ChampAPIPerformanceTest { //Ignore, no schema set } catch (ChampObjectNotExistsException e) { //Ignore, not an update - } + } catch (ChampTransactionException e) { + throw new RuntimeException(e); + } } final double totalElapsedTimeSecs = (System.nanoTime() - totalStartTime) / 1000.0 / 1000.0 / 1000.0; @@ -396,7 +422,7 @@ public class ChampAPIPerformanceTest { objects.get(i % objects.size()), objects.get((i + 1) % objects.size()), "bazz" ).property("relationshipNumber", i) .build() - ); + , Optional.empty()); final double elapsedMs = (System.nanoTime() - startTime) / 1000.0 / 1000.0; @@ -411,6 +437,8 @@ public class ChampAPIPerformanceTest { throw new RuntimeException(e); } catch (ChampUnmarshallingException e) { throw new RuntimeException(e); + } catch (ChampTransactionException e) { + throw new RuntimeException(e); } } diff --git a/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/concurrency/ConcurrencyTest.java b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/concurrency/ConcurrencyTest.java new file mode 100644 index 0000000..9e08f55 --- /dev/null +++ b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/concurrency/ConcurrencyTest.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champtitan.concurrency; + +import org.junit.Test; + +public class ConcurrencyTest { + + @Test + public void runInMemoryConcurrentTest() { + org.onap.aai.champcore.concurrency.ConcurrencyTest baseTest = new org.onap.aai.champcore.concurrency.ConcurrencyTest(); + baseTest.runConcurrentTest("TITAN"); + } +} diff --git a/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampAPITest.java b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampAPITest.java new file mode 100644 index 0000000..8d4bc57 --- /dev/null +++ b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampAPITest.java @@ -0,0 +1,40 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champtitan.core; + +import org.junit.Test; +import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl; + +public class ChampAPITest { + @Test + public void testChampGraphInstantiation() throws Exception { + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + + org.onap.aai.champcore.core.ChampAPITest baseTest = new org.onap.aai.champcore.core.ChampAPITest(); + + baseTest.testChampGraphInstantiation(graph); + } + + +} diff --git a/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampObjectIndexTest.java b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampObjectIndexTest.java new file mode 100644 index 0000000..bd9295f --- /dev/null +++ b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampObjectIndexTest.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champtitan.core; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onap.aai.champcore.exceptions.ChampIndexNotExistsException; +import org.onap.aai.champcore.model.ChampCardinality; +import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl; + +public class ChampObjectIndexTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void testChampObjectIndexCrud() throws Exception { + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + + org.onap.aai.champcore.core.ChampObjectIndexTest.testChampObjectIndexCrud(graph); + + graph.shutdown(); + + exception.expect(IllegalStateException.class); + graph.executeDeleteObjectIndex("any"); + } +} diff --git a/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampRelationshipIndexTest.java b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampRelationshipIndexTest.java new file mode 100644 index 0000000..e515101 --- /dev/null +++ b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampRelationshipIndexTest.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champtitan.core; + +import org.junit.Test; +import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl; + +public class ChampRelationshipIndexTest { + @Test + public void testChampRelationshipIndexCrud() { + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + org.onap.aai.champcore.core.ChampRelationshipIndexTest baseTest = new org.onap.aai.champcore.core.ChampRelationshipIndexTest(); + baseTest.testChampRelationshipIndexCrud(graph); + + graph.shutdown(); + } +} diff --git a/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampSchemaTest.java b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampSchemaTest.java new file mode 100644 index 0000000..ac29fc8 --- /dev/null +++ b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampSchemaTest.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.champtitan.core; + +import org.junit.Test; +import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl; + +public class ChampSchemaTest { + @Test + public void testChampSchemaCrud() { + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .property("storage.backend", "inmemory") + .build(); + org.onap.aai.champcore.core.ChampSchemaTest.testChampSchemaCrud(graph); + + graph.shutdown(); + } +} diff --git a/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampTransactionTest.java b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampTransactionTest.java new file mode 100644 index 0000000..aafc053 --- /dev/null +++ b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/ChampTransactionTest.java @@ -0,0 +1,335 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.champtitan.core; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Optional; +import java.util.concurrent.CountDownLatch; + +import org.junit.Before; +import org.junit.Test; +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.ChampRelationship; +import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl; + +public class ChampTransactionTest { + + public TitanChampGraphImpl graph = null; + public CountDownLatch latch = new CountDownLatch(2); + public ChampObject[] storedVertices = new ChampObject[2]; + + + @Before + public void setup() { + graph = new TitanChampGraphImpl.Builder("TransactionTestGraph") + .property("storage.backend", "inmemory") + .build(); + } + + + /** + * This test validates that multiple CRUD operations can be performed against vertices within + * the same transactional context and that, once the transaction is committed, the final + * state of the vertices reflects the sum of all of the operations performed within the + * transaction. + * + * @throws ChampMarshallingException + * @throws ChampSchemaViolationException + * @throws ChampObjectNotExistsException + * @throws ChampUnmarshallingException + * @throws ChampTransactionException + */ + @Test + public void champObjectSingleTxTest() throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampUnmarshallingException, ChampTransactionException { + + ChampObject v1 = ChampObject.create() + .ofType("foo") + .withoutKey() + .withProperty("property1", "value1") + .withProperty("property2", "value2") + .build(); + + ChampObject v2 = ChampObject.create() + .ofType("foo") + .withoutKey() + .withProperty("property3", "value3") + .withProperty("property4", "value4") + .build(); + + ChampObject v3 = ChampObject.create() + .ofType("foo") + .withoutKey() + .withProperty("property5", "value5") + .withProperty("property6", "value6") + .build(); + + ChampObject v4 = ChampObject.create() + .ofType("foo") + .withoutKey() + .withProperty("property7", "value7") + .withProperty("property8", "value8") + .build(); + + + // Open a transaction with the graph data store. + ChampTransaction tx = graph.openTransaction(); + + // Create all of our vertices. + ChampObject storedV1 = graph.storeObject(v1, Optional.of(tx)); + ChampObject storedV2 = graph.storeObject(v2, Optional.of(tx)); + ChampObject storedV3 = graph.storeObject(v3, Optional.of(tx)); + ChampObject storedV4 = graph.storeObject(v4, Optional.of(tx)); + + // Now, within the same transactional context, do a replacement against one of the + // vertices that we just created. + ChampObject replacedV2 = graph.replaceObject(ChampObject.create() + .ofType("foo") + .withKey(storedV2.getKey().get()) + .withProperty("replacedProperty3", "replacedValue3") + .withProperty("replacedProperty4", "replacedValue4") + .build(), + Optional.of(tx)); + + // Within the same transactional context, do an update against one of the vertices + // that we just created. + final ChampObject updatedV3 = graph.storeObject(ChampObject.create() + .from(storedV3) + .withKey(storedV3.getKey().get()) + .withProperty("updatedProperty", "updatedValue") + .build(), Optional.of(tx)); + + // Within the same transactional context, delete one of the vertices that we just + // created. + graph.deleteObject(storedV4.getKey().get(), Optional.of(tx)); + + // Finally, commit our transaction. + tx.commit(); + + tx = graph.openTransaction(); + + Optional<ChampObject> retrievedV1 = graph.retrieveObject(storedV1.getKey().get(), Optional.of(tx)); + assertTrue(retrievedV1.isPresent()); + assertTrue(retrievedV1.get().getProperty("property1").get().equals("value1")); + assertTrue(retrievedV1.get().getProperty("property2").get().equals("value2")); + + + Optional<ChampObject> retrievedV2 = graph.retrieveObject(storedV2.getKey().get(), Optional.of(tx)); + assertTrue(retrievedV2.isPresent()); + assertTrue(retrievedV2.get().getProperty("replacedProperty3").get().equals("replacedValue3")); + assertTrue(retrievedV2.get().getProperty("replacedProperty4").get().equals("replacedValue4")); + assertFalse(retrievedV2.get().getProperty("value3").isPresent()); + assertFalse(retrievedV2.get().getProperty("value4").isPresent()); + + Optional<ChampObject> retrievedV3 = graph.retrieveObject(storedV3.getKey().get(), Optional.of(tx)); + assertTrue(retrievedV3.isPresent()); + assertTrue(retrievedV3.get().getProperty("property5").get().equals("value5")); + assertTrue(retrievedV3.get().getProperty("property6").get().equals("value6")); + assertTrue(retrievedV3.get().getProperty("updatedProperty").get().equals("updatedValue")); + + + Optional<ChampObject> retrievedV4 = graph.retrieveObject(storedV4.getKey().get(), Optional.of(tx)); + assertFalse("Deleted vertex should not be present in graph", retrievedV4.isPresent()); + + tx.commit(); + } + + + /** + * This test validates that multiple threads can each open their own transactions with the + * graph data store, and that there is no leakage between each thread's transactions. + * + * @throws ChampMarshallingException + * @throws ChampSchemaViolationException + * @throws ChampObjectNotExistsException + * @throws ChampUnmarshallingException + * @throws ChampTransactionException + */ + @Test + public void multipleTransactionTest() throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampUnmarshallingException, ChampTransactionException { + + ChampObject v1 = ChampObject.create() + .ofType("foo") + .withoutKey() + .withProperty("property1", "value1") + .withProperty("property2", "value2") + .build(); + + ChampObject v2 = ChampObject.create() + .ofType("bar") + .withoutKey() + .withProperty("property3", "value3") + .withProperty("property4", "value4") + .build(); + + // Instantiate and start our two transactional worker threads... + Thread thread1 = new Thread(new VertexWriter(v1, 0)); + Thread thread2 = new Thread(new VertexWriter(v2, 1)); + thread1.start(); + thread2.start(); + + // and wait for the threads to complete. + try { + thread1.join(); + thread2.join(); + + } catch (InterruptedException e) { } + + // Now that all of our data has been committed, let's open a new transaction + // and verify that all of our vertices can be retrieved. + ChampTransaction tx3 = graph.openTransaction(); + + Optional<ChampObject> retrievedV1 = graph.retrieveObject(storedVertices[0].getKey().get(), Optional.of(tx3)); + assertTrue(retrievedV1.isPresent()); + Optional<ChampObject> retrievedV2 = graph.retrieveObject(storedVertices[1].getKey().get(), Optional.of(tx3)); + assertTrue(retrievedV2.isPresent()); + + tx3.commit(); + } + + + /** + * This method validates that edges can be successfully created within a single transaction. + * + * @throws ChampMarshallingException + * @throws ChampSchemaViolationException + * @throws ChampObjectNotExistsException + * @throws ChampUnmarshallingException + * @throws ChampRelationshipNotExistsException + * @throws ChampTransactionException + */ + @Test + public void edgeTest() throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampUnmarshallingException, ChampRelationshipNotExistsException, ChampTransactionException { + + // Create the source and target vertices for our edge. + final ChampObject source = ChampObject.create() + .ofType("foo") + .withoutKey() + .withProperty("property1", "value1") + .build(); + + final ChampObject target = ChampObject.create() + .ofType("foo") + .withoutKey() + .build(); + + // Open a transaction with the graph data store. + ChampTransaction tx = graph.openTransaction(); + + // Now, create our vertices. + ChampObject storedSource = graph.storeObject(source, Optional.of(tx)); + ChampObject storedTarget = graph.storeObject(target, Optional.of(tx)); + + // Create the edge between the vertices. + ChampRelationship relationship = new ChampRelationship.Builder(storedSource, storedTarget, "relationship") + .property("property-1", "value-1") + .property("property-2", 3) + .build(); + ChampRelationship storedRelationship = graph.storeRelationship(relationship, Optional.of(tx)); + + // Validate that we can read back the edge within the transactional context. + Optional<ChampRelationship> retrievedRelationship = graph.retrieveRelationship(storedRelationship.getKey().get(), Optional.of(tx)); + assertTrue("Failed to retrieve stored relationship", retrievedRelationship.isPresent()); + + // Commit our transaction. + graph.commitTransaction(tx); + + // Now, open a new transaction. + tx = graph.openTransaction(); + + // Now, read back the edge that we just created again, validating that it was + // successfully committed to the graph. + retrievedRelationship = graph.retrieveRelationship(storedRelationship.getKey().get(), Optional.of(tx)); + assertTrue("Failed to retrieve stored relationship", retrievedRelationship.isPresent()); + + graph.commitTransaction(tx); + } + + private class VertexWriter implements Runnable { + + ChampObject vertex; + int index; + + public VertexWriter(ChampObject vertex, int index) { + this.vertex = vertex; + this.index = index; + } + + public void run() { + + ChampTransaction tx=null; + try { + + // Open a threaded transaction to do some work in. + tx = graph.openTransaction(); + + // Now store one of our two vertices within the context of this transaction. + storedVertices[index] = graph.storeObject(vertex, Optional.of(tx)); + + // Use our latch to indicate that we are done creating vertices, and wait for + // the other thread to do the same. + latch.countDown(); + latch.await(); + + // Validate that the vertex we created is visible to us in the graph, but the + // one that the other thread created is not. + Optional<ChampObject> retrievedV2 = graph.retrieveObject(storedVertices[index].getKey().get(), Optional.of(tx)); + assertTrue(retrievedV2.isPresent()); + Optional<ChampObject> retrievedV1 = graph.retrieveObject(storedVertices[(index+1)%2].getKey().get(), Optional.of(tx)); + assertFalse(retrievedV1.isPresent()); + + } catch (InterruptedException | + ChampUnmarshallingException | + ChampMarshallingException | + ChampSchemaViolationException | + ChampObjectNotExistsException | ChampTransactionException e) { + + fail("Thread failed to interact with graph due to " + e.getMessage()); + + } finally { + + try { + Thread.sleep(index * 500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // Now, commit our transaction and bail... + try { + graph.commitTransaction(tx); + } catch (ChampTransactionException e) { + + } + } + } + }; +} + diff --git a/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/TitanChampSetupTest.java b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/TitanChampSetupTest.java new file mode 100644 index 0000000..bca61ec --- /dev/null +++ b/champ-lib/champ-titan/src/test/java/org/onap/aai/champtitan/core/TitanChampSetupTest.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.champtitan.core; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl; + +import java.util.HashMap; +import java.util.Map; + +public class TitanChampSetupTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void TitanSetupBadBackendTest() { + exception.expect(RuntimeException.class); + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .property("storage.backend", "bad-backend") + .build(); + } + + @Test + public void TitanSetupBerkleyBackendTest() { + exception.expect(RuntimeException.class); + Map<String, Object> propertiesMap = new HashMap<String, Object>(); + propertiesMap.put("storage.backend", "berkleyje"); + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .properties(propertiesMap) + .build(); + } + + @Test + public void TitanSetupBadPropertyTest() { + exception.expect(RuntimeException.class); + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .property("storage.backend", "in-memory") + .property("storage.cassandra.keyspace", "anything") + .build(); + } + + @Test + public void TitanSetupBadPropertiesTest() { + exception.expect(RuntimeException.class); + Map<String, Object> propertiesMap = new HashMap<String, Object>(); + propertiesMap.put("storage.cassandra.keyspace", "anything"); + + TitanChampGraphImpl graph = new TitanChampGraphImpl.Builder("testGraph") + .property("storage.backend", "in-memory") + .properties(propertiesMap) + .build(); + } +} diff --git a/champ-lib/pom.xml b/champ-lib/pom.xml new file mode 100644 index 0000000..771957a --- /dev/null +++ b/champ-lib/pom.xml @@ -0,0 +1,300 @@ +<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> + + <groupId>org.onap.aai</groupId> + <artifactId>champ-lib</artifactId> + <packaging>pom</packaging> + <version>1.2.0-SNAPSHOT</version> + + <modules> + <module>champ-core</module> + <module>champ-titan</module> + <module>champ-janus</module> + </modules> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <event.client.version>1.2.0</event.client.version> + + <!--<absoluteDistFilesRoot>/appl/${project.artifactId}</absoluteDistFilesRoot>--> + + <!--<!– For NO Versioning, REMOVE the /${project.version} from the <distFilesRoot>--> + <!--property, below. PLEASE, NOTE: If your ${project.version} is a "-SNAPSHOT"--> + <!--version, THIS will be used as your directory structure. If you do NOT want--> + <!--this, simply remove the "-SNAPSHOT" from your <version> declaration at the--> + <!--top of pom.xml –>--> + <!--<distFilesRoot>/appl/${project.artifactId}/${project.version}</distFilesRoot>--> + </properties> + + <scm> + <connection>scm:git:ssh://git@codecloud.web.att.com:7999/st_aai/champ.git</connection> + <tag>HEAD</tag> + </scm> + + <distributionManagement> + <!-- Repository to publish RELEASE artifacts to. --> + <repository> + <id>nexus</id> + <name>ecomp_aai-releases</name> + <url>http://mavencentral.it.att.com:8084/nexus/content/repositories/ecomp_aai-releases</url> + </repository> + <!-- Repository to publish SNAPSHOT artifacts to. --> + <snapshotRepository> + <id>nexus</id> + <name>ecomp_aai-snapshots</name> + <url>http://mavencentral.it.att.com:8084/nexus/content/repositories/ecomp_aai-snapshots</url> + </snapshotRepository> + </distributionManagement> + + <dependencyManagement> + <dependencies> + <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> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.2.1</version> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.apache.hbase</groupId> + <artifactId>hbase-client</artifactId> + <version>0.98.4-hadoop2</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>jdk.tools</groupId> + <artifactId>jdk.tools</artifactId> + <version>1.8</version> + <scope>system</scope> + <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath> + </dependency> + <dependency> + <groupId>org.jacoco</groupId> + <artifactId>org.jacoco.agent</artifactId> + <version>0.7.9</version> + <classifier>runtime</classifier> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.7.9</version> + <configuration> + <excludes> + <!-- These three need to be included again at some point --> + <exclude>**/AbstractGremlinChampGraph*</exclude> + <exclude>**/DseChampGraphImpl*</exclude> + <exclude>**/DseChampformer*</exclude> + <!-- Permanently excluded, not worth testing --> + <exclude>**/ChampAPIPerformanceTest*</exclude> + </excludes> + </configuration> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>default-report</id> + <phase>prepare-package</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + <execution> + <id>default-check</id> + <goals> + <goal>check</goal> + </goals> + <configuration> + <rules> + <!-- implementation is needed only for Maven 2 --> + <rule implementation="org.jacoco.maven.RuleConfiguration"> + <element>BUNDLE</element> + <limits> + <!-- implementation is needed only for Maven 2 --> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>INSTRUCTION</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>BRANCH</counter> + <value>COVEREDRATIO</value> + <minimum>.12</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>COMPLEXITY</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>LINE</counter> + <value>COVEREDRATIO</value> + <minimum>.10</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>METHOD</counter> + <value>COVEREDRATIO</value> + <minimum>.17</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>CLASS</counter> + <value>MISSEDCOUNT</value> + <maximum>5</maximum> + </limit> + </limits> + </rule> + </rules> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>3.0.0</version> + <configuration> + <descriptorRefs> + <descriptorRef>jar-with-dependencies</descriptorRef> + </descriptorRefs> + </configuration> + <executions> + <execution> + <id>make-jar-with-dependencies</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.6.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + <plugin> + <artifactId>maven-release-plugin</artifactId> + <version>2.4.2</version> + <dependencies> + <dependency> + <groupId>org.apache.maven.scm</groupId> + <artifactId>maven-scm-provider-gitexe</artifactId> + <version>1.8.1</version> + </dependency> + </dependencies> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>3.0.1</version> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.9.1</version> + <executions> + <execution> + <id>attach-javadocs</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.12.2</version> + <configuration> + <systemPropertyVariables> + <jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile> + </systemPropertyVariables> + </configuration> + </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-service-deps-janus/pom.xml b/champ-service-deps-janus/pom.xml new file mode 100644 index 0000000..9bc954c --- /dev/null +++ b/champ-service-deps-janus/pom.xml @@ -0,0 +1,125 @@ +<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> + + <groupId>org.onap.aai</groupId> + <artifactId>champ-service-deps-janus</artifactId> + <packaging>pom</packaging> + <version>1.2.0-SNAPSHOT</version> + + <properties> + <event.client.version>1.2.0</event.client.version> + </properties> + + <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> + + <dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ-janus</artifactId> + <version>1.2.0-SNAPSHOT</version> + <exclusions> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-dmaap</artifactId> + </exclusion> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-kafka</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.janusgraph</groupId> + <artifactId>janusgraph-cassandra</artifactId> + <version>0.1.1</version> + <optional>true</optional> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.janusgraph</groupId> + <artifactId>janusgraph-hbase</artifactId> + <version>0.1.1</version> + <optional>true</optional> + <exclusions> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>3.0.1</version> + <executions> + <execution> + <id>copy-janus-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <outputDirectory>../champ-service/target/graph-deps/janus-deps</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>false</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/champ-service-deps-titan/pom.xml b/champ-service-deps-titan/pom.xml new file mode 100644 index 0000000..f4f081d --- /dev/null +++ b/champ-service-deps-titan/pom.xml @@ -0,0 +1,122 @@ +<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> + + <groupId>org.onap.aai</groupId> + <artifactId>champ-service-deps-titan</artifactId> + <packaging>pom</packaging> + <version>1.2.0-SNAPSHOT</version> + + <properties> + <event.client.version>1.2.0</event.client.version> + </properties> + + <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> + <dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ-titan</artifactId> + <version>1.2.0-SNAPSHOT</version> + <exclusions> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-dmaap</artifactId> + </exclusion> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-kafka</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.thinkaurelius.titan</groupId> + <artifactId>titan-cassandra</artifactId> + <version>1.0.0</version> + <exclusions> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.thinkaurelius.titan</groupId> + <artifactId>titan-hbase</artifactId> + <version>1.0.0</version> + <exclusions> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>3.0.1</version> + <executions> + <execution> + <id>copy-titan-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <outputDirectory>../champ-service/target/graph-deps/titan-deps</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>false</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/champ-service/License.txt b/champ-service/License.txt new file mode 100644 index 0000000..469f362 --- /dev/null +++ b/champ-service/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-service/ajsc-shared-config/etc/logback.xml b/champ-service/ajsc-shared-config/etc/logback.xml new file mode 100644 index 0000000..12ed478 --- /dev/null +++ b/champ-service/ajsc-shared-config/etc/logback.xml @@ -0,0 +1,235 @@ +<!-- + + ============LICENSE_START========================================== + org.onap.aai + =================================================================== + Copyright © 2017 AT&T Intellectual Property. All rights reserved. + Copyright © 2017 Amdocs + =================================================================== + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for 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 scan="true" scanPeriod="3 seconds" debug="false"> + <!--<jmxConfigurator /> --> + <!-- directory path for all other type logs --> + + <property name="logDir" value="${AJSC_HOME}/logs" /> + + + <!-- specify the component name + <ECOMP-component-name>::= "MSO" | "DCAE" | "ASDC " | "AAI" |"Policy" | "SDNC" | "AC" --> + <property name="componentName" value="AAI-CHAMP" /> + + <!-- default eelf log file names --> + <property name="generalLogName" value="error" /> + <property name="metricsLogName" value="metrics" /> + <property name="auditLogName" value="audit" /> + <property name="debugLogName" value="debug" /> + + <property name="errorLogPattern" value="%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%mdc{RequestId}|%thread|champ-service|%mdc{PartnerName}|%logger||%.-5level|%msg%n" /> + <property name="auditMetricPattern" value="%m%n" /> + + <property name="logDirectory" value="${logDir}/${componentName}" /> + + <!-- Example evaluator filter applied against console appender --> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${errorLogPattern}</pattern> + </encoder> + </appender> + + <!-- ============================================================================ --> + <!-- EELF Appenders --> + <!-- ============================================================================ --> + + <!-- The EELFAppender is used to record events to the general application + log --> + + <appender name="EELF" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${generalLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/${generalLogName}.%d{yyyy-MM-dd}.log.zip + </fileNamePattern> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${errorLogPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELF" class="ch.qos.logback.classic.AsyncAppender"> + <!-- deny all events with a level below INFO, that is TRACE and DEBUG --> + <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> + <level>INFO</level> + </filter> + <queueSize>256</queueSize> + <appender-ref ref="EELF" /> + </appender> + + + <!-- EELF Audit Appender. This appender is used to record audit engine + related logging events. The audit logger and appender are specializations + of the EELF application root logger and appender. This can be used to segregate + Policy engine events from other components, or it can be eliminated to record + these events as part of the application root log. --> + + <appender name="EELFAudit" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${auditLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/${auditLogName}.%d{yyyy-MM-dd}.log.zip + </fileNamePattern> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${auditMetricPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELFAudit" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFAudit" /> + </appender> + + <appender name="EELFMetrics" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${metricsLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/${metricsLogName}.%d{yyyy-MM-dd}.log.zip + </fileNamePattern> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <!-- <pattern>"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - + %msg%n"</pattern> --> + <pattern>${auditMetricPattern}</pattern> + </encoder> + </appender> + + + <appender name="asyncEELFMetrics" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFMetrics"/> + </appender> + + <appender name="EELFDebug" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${debugLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/${debugLogName}.%d{yyyy-MM-dd}.log.zip + </fileNamePattern> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${errorLogPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFDebug" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFDebug" /> + <includeCallerData>false</includeCallerData> + </appender> + + + <!-- ============================================================================ --> + <!-- EELF loggers --> + <!-- ============================================================================ --> + <logger name="com.att.eelf" level="info" additivity="false"> + <appender-ref ref="asyncEELF" /> + <appender-ref ref="asyncEELFDebug" /> + </logger> + + <logger name="com.att.eelf.security" level="info" additivity="false"> + <appender-ref ref="asyncEELFSecurity" /> + </logger> + <logger name="com.att.eelf.perf" level="info" additivity="false"> + <appender-ref ref="asyncEELFPerformance" /> + </logger> + <logger name="com.att.eelf.server" level="info" additivity="false"> + <appender-ref ref="asyncEELFServer" /> + </logger> + <logger name="com.att.eelf.policy" level="info" additivity="false"> + <appender-ref ref="asyncEELFPolicy" /> + </logger> + <logger name="com.att.eelf.audit" level="info" additivity="false"> + <appender-ref ref="asyncEELFAudit" /> + </logger> + <logger name="com.att.eelf.metrics" level="info" additivity="false"> + <appender-ref ref="asyncEELFMetrics" /> + </logger> + + <!-- Spring related loggers --> + <logger name="org.springframework" level="WARN" /> + <logger name="org.springframework.beans" level="WARN" /> + <logger name="org.springframework.web" level="WARN" /> + <logger name="com.blog.spring.jms" level="WARN" /> + + <!-- AJSC Services (bootstrap services) --> + <logger name="ajsc" level="WARN" /> + <logger name="ajsc.RouteMgmtService" level="WARN" /> + <logger name="ajsc.ComputeService" level="WARN" /> + <logger name="ajsc.VandelayService" level="WARN" /> + <logger name="ajsc.FilePersistenceService" level="WARN" /> + <logger name="ajsc.UserDefinedJarService" level="WARN" /> + <logger name="ajsc.UserDefinedBeansDefService" level="WARN" /> + <logger name="ajsc.LoggingConfigurationService" level="WARN" /> + + <!-- AJSC related loggers (DME2 Registration, csi logging, restlet, servlet + logging) --> + <logger name="ajsc.utils" level="WARN" /> + <logger name="ajsc.utils.DME2Helper" level="WARN" /> + <logger name="ajsc.filters" level="WARN" /> + <logger name="ajsc.beans.interceptors" level="WARN" /> + <logger name="ajsc.restlet" level="WARN" /> + <logger name="ajsc.servlet" level="WARN" /> + <logger name="com.att" level="INFO" /> + <logger name="com.att.ajsc.csi.logging" level="WARN" /> + <logger name="com.att.ajsc.filemonitor" level="WARN" /> + + <!-- champ-service loggers --> + <logger name="org.onap.champ" level="INFO" /> + + <!-- Other Loggers that may help troubleshoot --> + <logger name="net.sf" level="WARN" /> + <logger name="org.apache" level="WARN" /> + <logger name="org.apache.commons.httpclient" level="WARN" /> + <logger name="org.apache.commons" level="WARN" /> + <logger name="org.apache.coyote" level="WARN" /> + <logger name="org.apache.jasper" level="WARN" /> + + <!-- Camel Related Loggers (including restlet/servlet/jaxrs/cxf logging. + May aid in troubleshooting) --> + <logger name="org.apache.camel" level="WARN" /> + <logger name="org.apache.cxf" level="WARN" /> + <logger name="org.apache.camel.processor.interceptor" level="WARN" /> + <logger name="org.apache.cxf.jaxrs.interceptor" level="WARN" /> + <logger name="org.apache.cxf.service" level="WARN" /> + <logger name="org.restlet" level="WARN" /> + <logger name="org.apache.camel.component.restlet" level="WARN" /> + + <!-- logback internals logging --> + <logger name="ch.qos.logback.classic" level="WARN" /> + <logger name="ch.qos.logback.core" level="WARN" /> + + <root> + <appender-ref ref="asyncEELF" /> + <!-- <appender-ref ref="asyncEELFDebug" /> --> + </root> + +</configuration> diff --git a/champ-service/antBuild/build.xml b/champ-service/antBuild/build.xml new file mode 100644 index 0000000..b898a9e --- /dev/null +++ b/champ-service/antBuild/build.xml @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project> + <target name="runLocal"> + <java dir="${basedir}" fork="yes" newenvironment="true" + failonerror="true" classname="com.att.ajsc.runner.Runner"> + <classpath + path="${classpath}:${basedir}/ajsc-shared-config/etc:${runAjscHome}/lib/ajsc-runner-${ajscRuntimeVersion}.jar" /> + + <!-- Windows Users may need to add a jvmarg arg to create a temp directory + properly. --> + <!-- <jvmarg value="-Djava.io.tmpdir=C:/yourTempDirectory"/> --> + + <!-- Uncomment the following 2 jvmarg values to enable Remote Debugging. + --> + <!-- <jvmarg value="-Xdebug" /> --> + <!-- <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5432" + /> --> + + <jvmarg value="-XX:MaxPermSize=512m" /> + <jvmarg value="-Xmx1024m" /> + + <!-- Main ajsc Variables below (Variables necessary for proper startup + of AJSC) --> + <env key="AJSC_HOME" value="${runAjscHome}" /> + <sysproperty key="AJSC_HOME" value="${runAjscHome}" /> + <!-- you may specify any external location for AJSC_CONF_HOME where etc + folder & all other configs can be found under it. If not specified, it will + default to AJSC_HOME --> + <sysproperty key="AJSC_CONF_HOME" value="${basedir}/bundleconfig-local" /> + <sysproperty key="AJSC_SHARED_CONFIG" value="${basedir}/ajsc-shared-config" /> + + <!-- Location of logback.xml file used for logging configurations. Please, + note, when deploying a service to either CSI or NON-CSI environment, this + system property will be set in sys-props.properties file. We are setting + it here for running locally due to the ease of use of maven variable for + basedir. --> + <sysproperty key="logback.configurationFile" + value="${basedir}/ajsc-shared-config/etc/logback.xml" /> + + <!-- Setting system properties for the AJSC external libs and properties + folders below. When deploying to a node, these properties will be set within + the bundleconfig/etc/sysprops/sys-props.properties file. However, when running + locally, the ${basedir} substitution works more efficiently in this manner. --> + <sysproperty key="AJSC_EXTERNAL_LIB_FOLDERS" value="${basedir}/target/commonLibs" /> + <sysproperty key="AJSC_EXTERNAL_PROPERTIES_FOLDERS" + value="${basedir}/ajsc-shared-config/etc" /> + + <!-- End of Main ajsc Variables below (Variables necessary for proper + startup of AJSC) --> + + <!-- Uncomment the following line to add oauthentication to your Service --> + <!-- <sysproperty key="spring.profiles.active" value="oauth" /> --> + + <!-- If using Cassandra as Database, Enter the ip/host and port below + based on your known configuration --> + <!-- <sysproperty key="cassandra.ip" value="hostname" /> --> + <!-- <sysproperty key="cassandra.port" value="9042" /> --> + + <!-- The APP_SERVLET_URL_PATTERN variable is defaulted to "/services" + within the initial configuration of the AJSC. If you are changing the CamelServlet + Filter within the ajsc-override-web.xml, you should use that url-pattern + here. This is necessary to properly register your service with dme2. An empty + value, "", is used when NO value is wanted (url-pattern would be /* for CamelServlet + Filter) --> + <!-- As of 4.5.1, this property is no longer needed --> + <!-- <sysproperty key="APP_SERVLET_URL_PATTERN" value="/services" /> --> + + <!-- GRM/DME2 System Properties below --> + <sysproperty key="AJSC_SERVICE_NAMESPACE" value="${module.ajsc.namespace.name}" /> + <sysproperty key="AJSC_SERVICE_VERSION" value="${module.ajsc.namespace.version}" /> + <sysproperty key="SOACLOUD_SERVICE_VERSION" value="${project.version}" /> + <!-- End of GRM/DME2 System Property Variables --> + + <!-- The following server.port variable was necessary for the proper registration + of the AJSC to dme2. This value may still need to be used if the Developer + is hardcoding their port (example: 8080). Then, the server.port value="8080". + The default functionality for the AJSC is to use EPHEMERAL ports. In this + case, you do NOT need to set the server.port value. The AJSC will find the + proper port value and register to dme2 correctly --> + <!-- <sysproperty key="server.port" value="${serverPort}" /> --> + + <!-- Command Line Arguments to add to the java command. Here, you can + specify the port as well as the Context you want your service to run in. + Use context=/ to run in an unnamed Context (Root Context). The default configuration + of the AJSC is to run under the /ajsc Context. Setting the port here can + aid during the development phase of your service. However, you can leave + this argument out entirely, and the AJSC will default to using an Ephemeral + port. --> + <arg line="context=/ port=${serverPort} sslport=${sslport}" /> + </java> + </target> + <target name="prep_home_directory_for_swm_pkgcreate"> + + + <!-- These tasks are copying contents from the installHomeDirectory into + the eventual $AJSC_HOME directory for running locally and soa cloud installation --> + <echo message="ENTERING 'prep_home_directory_for_swm_pkgcreate' ant tasks" /> + + <copy + toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/bundleconfig" + failonerror="true"> + <fileset dir="${basedir}/bundleconfig-local" includes="**/**" /> + </copy> + <copy + toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/bundleconfig/etc" + failonerror="true"> + <fileset dir="${basedir}/ajsc-shared-config/etc" includes="**/**" /> + </copy> + <!-- End of NON-CSI related build copy task. --> + + <!-- Copying any zips (deployment packages) to $AJSC_HOME/services for + auto-deployment --> + <copy + toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/services" + failonerror="false"> + <fileset dir="${basedir}/services" includes="*.zip" /> + </copy> + + <!-- Copying runtimeEnvironment zip file to $AJSC_HOME/runtime and renaming + runtimeEnvironment.zip for proper auto-deployment of ajsc services. + <copy + tofile="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/runtime/runtimeEnvironment.zip"> + <fileset dir="target" includes="*-runtimeEnvironment.zip" /> + </copy>--> + + <!-- Copying dependencies from the service project (not provided by AJSC + Container) to the $AJSC_HOME/extJars folder to be accessible on the classpath --> + <copy + toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/extJars" + failonerror="false"> + <fileset dir="target/userjars" includes="*" /> + </copy> + + <!-- extApps directory MUST be created for ajsc-runner to run correctly, + even if empty. DO NOT REMOVE!!! --> + <!-- extApps directory created to deploy other war files on startup or + hot deploy War files after ajsc starts up. --> + <mkdir + dir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/extApps" /> + + <!-- Copying any extra wars to $AJSC_HOME/extApps to be deployed within + AJSC --> + <copy + toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/extApps" + failonerror="false"> + <fileset dir="${basedir}/src/main/resources/extApps" + includes="*" /> + </copy> + + <!-- staticContent folder is for serving static content within an ajsc + service. Any static content to be served will be copyied to the ultimate + $AJSC_HOME/staticContent folder and can be served with the att-static-content + camel component. --> + <!-- Uncomment the following snippet to copy items from staticContent folder + to ultimate $AJSC_HOME/staticConent --> + <!-- <copy toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/staticContent" + failonerror="false"> <fileset dir="${basedir}/staticContent" includes="**/**" + /> </copy> --> + + <!-- Copying extra jar files that have been labeled as dependencies in + service project to /extJars folder to be made available on the classpath + for your service --> + <copy + toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/extJars" + failonerror="false"> + <fileset dir="target" includes="*.jar" /> + </copy> + + <!-- Copying deployment packages created within the project to the $AJSC_HOME/services + folder to be auto deployed. --> + <copy + toDir="${basedir}/target/swm/package/nix/dist_files${distFilesRoot}/services"> + <fileset dir="target" includes="*.zip" excludes="*-runtimeEnvironment.zip" /> + </copy> + + <echo message="EXITING 'prep_assembly_output_for_swm_plugin' ant tasks" /> + </target> +</project> diff --git a/champ-service/appconfig-local/auth/champion-service_policy.json-REPLACE b/champ-service/appconfig-local/auth/champion-service_policy.json-REPLACE new file mode 100644 index 0000000..ee9bf44 --- /dev/null +++ b/champ-service/appconfig-local/auth/champion-service_policy.json-REPLACE @@ -0,0 +1 @@ +This should be replaced with an actual policy file
\ No newline at end of file diff --git a/champ-service/appconfig-local/auth/tomcat_keystore-REPLACE b/champ-service/appconfig-local/auth/tomcat_keystore-REPLACE new file mode 100644 index 0000000..cfc37ff --- /dev/null +++ b/champ-service/appconfig-local/auth/tomcat_keystore-REPLACE @@ -0,0 +1 @@ +Place keystore here
\ No newline at end of file diff --git a/champ-service/appconfig-local/champ-api.properties-REPLACE b/champ-service/appconfig-local/champ-api.properties-REPLACE new file mode 100644 index 0000000..9ad9b33 --- /dev/null +++ b/champ-service/appconfig-local/champ-api.properties-REPLACE @@ -0,0 +1,7 @@ +Replace with your actual properties file. Should contain something like: + +keyName=aai-uuid +sourceOfTruthName=source-of-truth +createdTsName=aai-created-ts +lastModTsName=aai-last-mod-ts +collectionPropertiesKey=properties
\ No newline at end of file diff --git a/champ-service/bundleconfig-local/etc/appprops/AAFUserRoles.properties b/champ-service/bundleconfig-local/etc/appprops/AAFUserRoles.properties new file mode 100644 index 0000000..dde7e09 --- /dev/null +++ b/champ-service/bundleconfig-local/etc/appprops/AAFUserRoles.properties @@ -0,0 +1,12 @@ + +#If using AAF for Role based authentication/authorization, define your routes/services which will utilize AAF. The AJSC will +#read this file and protect the routes given with the AAF role defined. + +#The following example would protect the JAXRS echo example service provided with the archetype. +#/services/${namespace}/v1/jaxrs-services/jaxrsExample/echo/*=com.att.ajsc.myper|mymachine|manage + +#The following example would protect ALL AJSC services running within your project. +#/**=com.att.ajsc.myperm|mymachine|manage + +#The following example would protect ALL REST services utilizing the Camel restlet routes. +#/rest/**=com.att.ajsc.myperm|mymachine|manage diff --git a/champ-service/bundleconfig-local/etc/appprops/PostProcessorInterceptors.properties b/champ-service/bundleconfig-local/etc/appprops/PostProcessorInterceptors.properties new file mode 100644 index 0000000..17b5036 --- /dev/null +++ b/champ-service/bundleconfig-local/etc/appprops/PostProcessorInterceptors.properties @@ -0,0 +1,2 @@ +#This properties file is for defining any PostProcessorInterceptors that have been created for your AJSC service. + diff --git a/champ-service/bundleconfig-local/etc/appprops/PreProcessorInterceptors.properties b/champ-service/bundleconfig-local/etc/appprops/PreProcessorInterceptors.properties new file mode 100644 index 0000000..ddaefdd --- /dev/null +++ b/champ-service/bundleconfig-local/etc/appprops/PreProcessorInterceptors.properties @@ -0,0 +1,3 @@ +#This properties file is for defining any PreProcessorInterceptors that have been created for your AJSC service. + +/**=com.att.ajsc.csi.restmethodmap.RestMethodMapInterceptor diff --git a/champ-service/bundleconfig-local/etc/appprops/app-intercepts.properties b/champ-service/bundleconfig-local/etc/appprops/app-intercepts.properties new file mode 100644 index 0000000..bcf3912 --- /dev/null +++ b/champ-service/bundleconfig-local/etc/appprops/app-intercepts.properties @@ -0,0 +1,7 @@ + +#This is where all your application intercept strategies must be configured. AJSC reads this property file and adds +#the list of intercepts specified here to the camel context. This can be useful for accessing every exchange object transferred from/to +#each endpoint in the request/response flow and can allow for more precise debugging and/or processing of the exchange. + +#e.g. +#intercepts=org.openecomp.champ.JaxrsEchoService,packagename.class1name,packagename.class2name diff --git a/champ-service/bundleconfig-local/etc/appprops/methodMapper.properties b/champ-service/bundleconfig-local/etc/appprops/methodMapper.properties new file mode 100644 index 0000000..1cda3e5 --- /dev/null +++ b/champ-service/bundleconfig-local/etc/appprops/methodMapper.properties @@ -0,0 +1,45 @@ +// +// Json object holds the method mapping.Update the JSON object with the proper route to logical mapping based +// on the example provided below : +// "helloWorld" = Service Name +// "method" = http method +// "url" = the url component from the route +// "logicalName"= When a combination of method and url from the route matches the json object , +// the logical name is put in the http header as "x-CSI-ServiceName" and "x-CSI-MethodName" +// "dme2url"= if provided it register the endpoint to GRM, it is optional. This is useful for JAX-RS services. + +{ + "helloWorld": [ + { + "method": "get", + "url": "/rest/champ-service/v1/helloWorld", + "logicalName": "GetMethod(Logical)" + }, + { + "method": "get", + "url": "/services/champ-service/v1/jaxrsExample/jaxrs-services/echo/{input}", + "logicalName": "GetJaxrsExampleEcho(Logical)", + "dme2url": "/services/champ-service/v1/jaxrsExample/jaxrs-services/echo/{input}" + }, + { + "method": "get", + "url": "/services/champ-service/v1/jaxrsExample/jaxrs-services/property/{fileName}/{input}", + "logicalName": "GetJaxrsExampleProperty(Logical)", + "dme2url": "/services/champ-service/v1/jaxrsExample/jaxrs-services/property/{fileName}/{input}" + } + ], + "errormessage": + [ + { + "method": "get", + "url": "/services/champ-service/v1/jaxrsExample/errormessage/emls", + "logicalName": "setCAETHeaders(Logical)" + }, + { + "method": "get", + "url": "/services/champ-service/v1/errorMessageLookupService2", + "logicalName": "setCAETHeaders(Logical)" + } + + ] +}
\ No newline at end of file diff --git a/champ-service/bundleconfig-local/etc/sysprops/sys-props.properties b/champ-service/bundleconfig-local/etc/sysprops/sys-props.properties new file mode 100644 index 0000000..26cd13d --- /dev/null +++ b/champ-service/bundleconfig-local/etc/sysprops/sys-props.properties @@ -0,0 +1,117 @@ +#This file is used for defining AJSC system properties for different configuration schemes and is necessary for the AJSC to run properly. +#The sys-props.properties file is used for running locally. The template.sys-props.properties file will be used when deployed +#to a SOA/CSI Cloud node. + +#AJSC System Properties. The following properties are required for ALL AJSC services. If you are adding System Properties for your +#particular service, please add them AFTER all AJSC related System Properties. + +#For Cadi Authorization, use value="authentication-scheme-1 +CadiAuthN=authentication-scheme-1 + +#For Basic Authorization, use value="authentication-scheme-1 +authN=authentication-scheme-2 + +#Persistence used for AJSC meta-data storage. For most environments, "file" should be used. +ajscPersistence=file + +#For Direct Invocation to be enabled (values=true/false) +directInvocationEnable=false + +# If using hawtio for local development, these properties will allow for faster server startup and usage for local development + +hawtio.authenticationEnabled=false +hawtio.config.pullOnStartup=false + +#Removes the extraneous restlet console output +org.restlet.engine.loggerFacadeClass=org.restlet.ext.slf4j.Slf4jLoggerFacade + +#server.host property to be enabled for local DME2 related testing +#server.host=<Your network IP address> + +#Enable/disable SSL (values=true/false). This property also determines which protocol to use (https if true, http otherwise), to register services into GRM through DME2. +enableSSL=false + + +#Enable/disable EJB Container +ENABLE_EJB=false + +#Enable/disable OSGI +isOSGIEnable=false + +#Generate/Skip api docs +isApiDoc=false + +#CSI related variables for CSM framework +csm.hostname=servername + + +#SOA_CLOUD_ENV is used to register your service with dme2 and can be turned off for local development (values=true/false). +SOA_CLOUD_ENV=false + +#CONTINUE_ON_LISTENER_EXCEPTION will exit the application if there is a DME2 exception at the time of registration. +CONTINUE_ON_LISTENER_EXCEPTION=false + +#Jetty Container ThreadCount Configuration Variables +AJSC_JETTY_ThreadCount_MIN=1 +AJSC_JETTY_ThreadCount_MAX=200 +AJSC_JETTY_IDLETIME_MAX=3000 + +#Camel Context level default threadPool Profile configuration +CAMEL_POOL_SIZE=10 +CAMEL_MAX_POOL_SIZE=20 +CAMEL_KEEP_ALIVE_TIME=60 +CAMEL_MAX_QUEUE_SIZE=1000 + +#GRM/DME2 System Properties +AFT_DME2_CONN_IDLE_TIMEOUTMS=5000 +AJSC_ENV=SOACLOUD + +SOACLOUD_NAMESPACE=com.att.ajsc +SOACLOUD_ENV_CONTEXT=DEV +SOACLOUD_PROTOCOL=http +SOACLOUD_ROUTE_OFFER=DEFAULT + +AFT_LATITUDE=23.4 +AFT_LONGITUDE=33.6 +AFT_ENVIRONMENT=AFTUAT + +#Restlet Component Default Properties +RESTLET_COMPONENT_CONTROLLER_DAEMON=true +RESTLET_COMPONENT_CONTROLLER_SLEEP_TIME_MS=100 +RESTLET_COMPONENT_INBOUND_BUFFER_SIZE=8192 +RESTLET_COMPONENT_MIN_THREADS=1 +RESTLET_COMPONENT_MAX_THREADS=10 +RESTLET_COMPONENT_LOW_THREADS=8 +RESTLET_COMPONENT_MAX_QUEUED=0 +RESTLET_COMPONENT_MAX_CONNECTIONS_PER_HOST=-1 +RESTLET_COMPONENT_MAX_TOTAL_CONNECTIONS=-1 +RESTLET_COMPONENT_OUTBOUND_BUFFER_SIZE=8192 +RESTLET_COMPONENT_PERSISTING_CONNECTIONS=true +RESTLET_COMPONENT_PIPELINING_CONNECTIONS=false +RESTLET_COMPONENT_THREAD_MAX_IDLE_TIME_MS=60000 +RESTLET_COMPONENT_USE_FORWARDED_HEADER=false +RESTLET_COMPONENT_REUSE_ADDRESS=true + +#Externalized jar and properties file location. In CSI environments, there are a few libs that have been externalized to aid +#in CSTEM maintenance of the versions of these libs. The most important to the AJSC is the DME2 lib. Not only is this lib necessary +#for proper registration of your AJSC service on a node, but it is also necessary for running locally as well. Another framework +#used in CSI envs is the CSM framework. These 2 framework libs are shown as "provided" dependencies within the pom.xml. These +#dependencies will be copied into the target/commonLibs folder with the normal "mvn clean package" goal of the AJSC. They will +#then be added to the classpath via AJSC_EXTERNAL_LIB_FOLDERS system property. Any files (mainly property files) that need +#to be on the classpath should be added to the AJSC_EXTERNAL_PROPERTIES_FOLDERS system property. The default scenario when +#testing your AJSC service locally will utilize the target/commonLibs directory for DME2 and CSM related artifacts and 2 +#default csm properties files will be used for local testing with anything CSM knorelated. +#NOTE: we are using maven-replacer-plugin to replace "(doubleUnderscore)basedir(doubleUnderscore)" with ${basedir} within the +#target directory for running locally. Multiple folder locations can be separated by the pipe ("|") character. +#Please, NOTE: for running locally, we are setting this system property in the antBuild/build.xml "runLocal" target and in the +#"runAjsc" profile within the pom.xml. This is to most effectively use maven variables (${basedir}, most specifically. Therefore, +#when running locally, the following 2 properties should be set within the profile(s) themselves. +#Example: target/commonLibs|target/otherLibs +#AJSC_EXTERNAL_LIB_FOLDERS=__basedir__/target/commonLibs +#AJSC_EXTERNAL_PROPERTIES_FOLDERS=__basedir__/ajsc-shared-config/etc +#End of AJSC System Properties + +#Service System Properties. Please, place any Service related System Properties below. + +KEY_STORE_PASSWORD=OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10 +KEY_MANAGER_PASSWORD=OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10 diff --git a/champ-service/pom.xml b/champ-service/pom.xml new file mode 100644 index 0000000..9edf59d --- /dev/null +++ b/champ-service/pom.xml @@ -0,0 +1,360 @@ +<?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> + <groupId>com.att.ajsc</groupId> + <artifactId>ajsc-archetype-parent</artifactId> + <version>2.0.0</version> + </parent> + + <groupId>org.onap.aai</groupId> + <artifactId>champ-service</artifactId> + <version>1.2.0-SNAPSHOT</version> + + <properties> + <runAjscHome>${basedir}/target/swm/package/nix/dist_files${distFilesRoot}</runAjscHome> + <ajscRuntimeVersion>2.0.0</ajscRuntimeVersion> + + <absoluteDistFilesRoot>/appl/${project.artifactId}</absoluteDistFilesRoot> + + <!-- For NO Versioning, REMOVE the /${project.version} from the <distFilesRoot> + property, below. PLEASE, NOTE: If your ${project.version} is a "-SNAPSHOT" + version, THIS will be used as your directory structure. If you do NOT want + this, simply remove the "-SNAPSHOT" from your <version> declaration at the + top of pom.xml --> + <distFilesRoot>/appl/${project.artifactId}/${project.version}</distFilesRoot> + + <event.client.version>1.2.0</event.client.version> + <common.logging.groupid>org.onap.aai.logging-service</common.logging.groupid> + <common.logging.version>1.2.0</common.logging.version> + </properties> + + <dependencies> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-core</artifactId> + <version>1.18.6</version> + </dependency> + + <!-- AJSC Dependencies --> + <dependency> + <groupId>dom4j</groupId> + <artifactId>dom4j</artifactId> + <version>1.6.1</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.att.aft</groupId> + <artifactId>dme2</artifactId> + <version>3.1.200</version> + <scope>provided</scope> + </dependency> + + <!--Adding this dependency explicit.--> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20160212</version> + </dependency> + + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-client</artifactId> + <version>2.23</version> + </dependency> + + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + </dependency> + + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.6.2</version> + </dependency> + + <dependency> + <groupId>${common.logging.groupid}</groupId> + <artifactId>common-logging</artifactId> + <version>${common.logging.version}</version> + </dependency> + + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + <version>1.1.7</version> + </dependency> + + <dependency> + <groupId>org.eclipse.persistence</groupId> + <artifactId>eclipselink</artifactId> + <version>2.6.2</version> + </dependency> + + <!-- 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> + + <!-- Champ graph database library. --> + <dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ-core</artifactId> + <version>1.2.0-SNAPSHOT</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <groupId>org.apache.hbase</groupId> + <artifactId>hbase-client</artifactId> + </exclusion> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-dmaap</artifactId> + </exclusion> + <exclusion> + <groupId>org.onap.aai.event-client</groupId> + <artifactId>event-client-kafka</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>2.7</version> + <executions> + <execution> + <id>copy-docker-file</id> + <phase>package</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>target</outputDirectory> + <overwrite>true</overwrite> + <resources> + <resource> + <directory>${basedir}/src/main/docker</directory> + <filtering>true</filtering> + <includes> + <include>**/*</include> + </includes> + </resource> + <resource> + <directory>${basedir}/src/main/bin/</directory> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.7.9</version> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>default-report</id> + <phase>prepare-package</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + <execution> + <id>default-check</id> + <goals> + <goal>check</goal> + </goals> + <configuration> + <rules> + <!-- implementation is needed only for Maven 2 --> + <rule implementation="org.jacoco.maven.RuleConfiguration"> + <element>BUNDLE</element> + <limits> + <!-- implementation is needed only for Maven 2 --> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>INSTRUCTION</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>BRANCH</counter> + <value>COVEREDRATIO</value> + <minimum>.12</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>COMPLEXITY</counter> + <value>COVEREDRATIO</value> + <minimum>.15</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>LINE</counter> + <value>COVEREDRATIO</value> + <minimum>.10</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>METHOD</counter> + <value>COVEREDRATIO</value> + <minimum>.17</minimum> + </limit> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>CLASS</counter> + <value>MISSEDCOUNT</value> + <maximum>5</maximum> + </limit> + </limits> + </rule> + </rules> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>runAjsc</id> + <build> + <defaultGoal>initialize</defaultGoal> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.3.2</version> + <executions> + <execution> + <phase>initialize</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <includeProjectDependencies>false</includeProjectDependencies> + <includePluginDependencies>true</includePluginDependencies> + <executable>java</executable> + <mainClass>com.att.ajsc.runner.Runner</mainClass> + <executableDependency> + <groupId>com.att.ajsc</groupId> + <artifactId>ajsc-runner</artifactId> + </executableDependency> + <additionalClasspathElements> + <additionalClasspathElement>${basedir}/ajsc-shared-config/etc</additionalClasspathElement> + </additionalClasspathElements> + + <environmentVariables> + <AJSC_HOME>${runAjscHome}</AJSC_HOME> + </environmentVariables> + + <!-- Main AJSC System Properties below (necessary for proper startup) --> + <systemProperties> + <systemProperty> + <key>AJSC_HOME</key> + <value>${runAjscHome}</value> + </systemProperty> + <systemProperty> + <key>CONFIG_HOME</key> + <value>${basedir}/appconfig-local/</value> + </systemProperty> + <systemProperty> + <key>AJSC_CONF_HOME</key> + <value>${basedir}/bundleconfig-local</value> + </systemProperty> + <systemProperty> + <key>logback.configurationFile</key> + <value>${basedir}/ajsc-shared-config/etc/logback.xml</value> + </systemProperty> + <systemProperty> + <key>AJSC_SHARED_CONFIG</key> + <value>${basedir}/ajsc-shared-config</value> + </systemProperty> + + <sysproperty> + <key>AJSC_EXTERNAL_LIB_FOLDERS</key> + <value>${basedir}/target/commonLibs</value> + </sysproperty> + <sysproperty> + <key>AJSC_EXTERNAL_PROPERTIES_FOLDERS</key> + <value>${basedir}/ajsc-shared-config/etc</value> + </sysproperty> + + <systemProperty> + <key>AJSC_SERVICE_NAMESPACE</key> + <value>${module.ajsc.namespace.name}</value> + </systemProperty> + <systemProperty> + <key>AJSC_SERVICE_VERSION</key> + <value>${module.ajsc.namespace.version}</value> + </systemProperty> + <systemProperty> + <key>SOACLOUD_SERVICE_VERSION</key> + <value>${project.version}</value> + </systemProperty> + <systemProperty> + <key>server.port</key> + <value>${serverPort}</value> + </systemProperty> + </systemProperties> + + <!-- Command Line Arguments to add to the java command. Here, you + can specify the port as well as the Context you want your service to run + in. Use context=/ to run in an unnamed Context (Root Context). The default + configuration of the AJSC is to run under the / Context. Setting the port + here can aid during the development phase of your service. However, you can + leave this argument out entirely, and the AJSC will default to using an Ephemeral + port. --> + <arguments> + <argument>context=/</argument> + <argument>port=${serverPort}</argument> + <argument>sslport=${sslport}</argument> + </arguments> + </configuration> + </execution> + </executions> + <configuration> + <executable>java</executable> + </configuration> + <dependencies> + <dependency> + <groupId>com.att.ajsc</groupId> + <artifactId>ajsc-runner</artifactId> + <version>${ajscRuntimeVersion}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </build> + </profile> + </profiles> +</project> diff --git a/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/conf/jaxrsBeans.groovy b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/conf/jaxrsBeans.groovy new file mode 100644 index 0000000..17d80a4 --- /dev/null +++ b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/conf/jaxrsBeans.groovy @@ -0,0 +1,11 @@ +beans{ + xmlns cxf: "http://camel.apache.org/schema/cxf" + xmlns jaxrs: "http://cxf.apache.org/jaxrs" + xmlns util: "http://www.springframework.org/schema/util" + + echoService(org.onap.champ.service.EchoService) + + util.list(id: 'echoServices') { + ref(bean:'echoService') + } +}
\ No newline at end of file diff --git a/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/docs/README.txt b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/docs/README.txt new file mode 100644 index 0000000..3707179 --- /dev/null +++ b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/docs/README.txt @@ -0,0 +1 @@ +Place any docs here that you want to access within the ajsc upon deployment of your service. diff --git a/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/lib/README.txt b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/lib/README.txt new file mode 100644 index 0000000..639e21b --- /dev/null +++ b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/lib/README.txt @@ -0,0 +1 @@ +3rd party JAR's needed by your jars (if any) for a ajsc deployment package go here...
\ No newline at end of file diff --git a/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/routes/champ.route b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/routes/champ.route new file mode 100644 index 0000000..cf8d115 --- /dev/null +++ b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/routes/champ.route @@ -0,0 +1,4 @@ +<route xmlns="http://camel.apache.org/schema/spring" trace="true"> + <from uri="att-dme2-servlet:///champ-service/v1/?matchOnUriPrefix=true" /> + <to uri="cxfbean:champRestService" /> +</route>
\ No newline at end of file diff --git a/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/routes/jaxrsExample.route b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/routes/jaxrsExample.route new file mode 100644 index 0000000..a132030 --- /dev/null +++ b/champ-service/src/main/ajsc/champ-service_v1/champ-service/v1/routes/jaxrsExample.route @@ -0,0 +1,5 @@ +<route xmlns="http://camel.apache.org/schema/spring" trace="true"> + <from uri="att-dme2-servlet:///echo-service/?matchOnUriPrefix=true" /> + <to uri="cxfbean:echoServices" /> +</route> + diff --git a/champ-service/src/main/assemble/ajsc_module_assembly.xml b/champ-service/src/main/assemble/ajsc_module_assembly.xml new file mode 100644 index 0000000..4ec4e28 --- /dev/null +++ b/champ-service/src/main/assemble/ajsc_module_assembly.xml @@ -0,0 +1,66 @@ +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> + <id>${version}</id> + <includeBaseDirectory>false</includeBaseDirectory> + <formats> + <format>zip</format> + </formats> + <fileSets> + <fileSet> + <directory>${project.basedir}/target/versioned-ajsc/routes/</directory> + <outputDirectory>${module.ajsc.namespace.name}/${module.ajsc.namespace.version}/routes/</outputDirectory> + <includes> + <include>*.route</include> + </includes> + + </fileSet> + + <fileSet> + <directory>${project.basedir}/target/versioned-ajsc/docs/</directory> + <outputDirectory>${module.ajsc.namespace.name}/${module.ajsc.namespace.version}/docs/</outputDirectory> + <includes> + <include>*.*</include> + <!-- <include>*.vm</include> --> + </includes> + + </fileSet> + + <fileSet> + <directory>${project.basedir}/target/versioned-ajsc/lib/</directory> + <outputDirectory>${module.ajsc.namespace.name}/${module.ajsc.namespace.version}/lib/</outputDirectory> + <includes> + <include>*.jar</include> + </includes> + + </fileSet> + <fileSet> + <directory>${project.basedir}/target/versioned-ajsc/extJars/</directory> + <outputDirectory>${module.ajsc.namespace.name}/${module.ajsc.namespace.version}/extJars/</outputDirectory> + <includes> + <include>*.jar</include> + </includes> + </fileSet> + + <!-- also try to grab outputs from the "jar" plugin's package phase --> + <fileSet> + <directory>${project.basedir}/target/</directory> + <outputDirectory>${module.ajsc.namespace.name}/${module.ajsc.namespace.version}/lib/</outputDirectory> + <includes> + <include>*.jar</include> + </includes> + </fileSet> + + <fileSet> + <directory>${project.basedir}/target/versioned-ajsc/conf/</directory> + <outputDirectory>${module.ajsc.namespace.name}/${module.ajsc.namespace.version}/conf/</outputDirectory> + <includes> + <include>*.*</include> + </includes> + + </fileSet> + </fileSets> + +</assembly> + diff --git a/champ-service/src/main/assemble/ajsc_props_assembly.xml b/champ-service/src/main/assemble/ajsc_props_assembly.xml new file mode 100644 index 0000000..5b8a6fa --- /dev/null +++ b/champ-service/src/main/assemble/ajsc_props_assembly.xml @@ -0,0 +1,23 @@ +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> + <id>${version}_properties</id> + <includeBaseDirectory>false</includeBaseDirectory> + <formats> + <format>zip</format> + </formats> + <fileSets> + <fileSet> + <directory>${project.basedir}/target/versioned-ajsc/props</directory> + <outputDirectory>${module.ajsc.namespace.name}/${module.ajsc.namespace.version}/props/</outputDirectory> + <includes> + <include>*.props</include> + </includes> + + </fileSet> + + </fileSets> + +</assembly> + diff --git a/champ-service/src/main/assemble/ajsc_runtime_assembly.xml b/champ-service/src/main/assemble/ajsc_runtime_assembly.xml new file mode 100644 index 0000000..e37d366 --- /dev/null +++ b/champ-service/src/main/assemble/ajsc_runtime_assembly.xml @@ -0,0 +1,44 @@ +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> + <id>runtimeEnvironment</id> + <includeBaseDirectory>false</includeBaseDirectory> + <formats> + <format>zip</format> + </formats> + <fileSets> + <fileSet> + <directory>${project.basedir}/target/versioned-runtime/context/</directory> + <outputDirectory>runtime/context/</outputDirectory> + <includes> + <include>*.context</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.basedir}/target/versioned-runtime/serviceProperties/</directory> + <outputDirectory>runtime/serviceProperties/</outputDirectory> + <includes> + <include>*.props</include> + </includes> + </fileSet><fileSet> + <directory>${project.basedir}/target/versioned-runtime/shiroRole</directory> + <outputDirectory>runtime/shiroRole/</outputDirectory> + <includes> + <include>*.json</include> + </includes> + </fileSet><fileSet> + <directory>${project.basedir}/target/versioned-runtime/shiroUser</directory> + <outputDirectory>runtime/shiroUser/</outputDirectory> + <includes> + <include>*.json</include> + </includes> + </fileSet><fileSet> + <directory>${project.basedir}/target/versioned-runtime/shiroUserRole</directory> + <outputDirectory>runtime/shiroUserRole</outputDirectory> + <includes> + <include>*.json</include> + </includes> + </fileSet> + </fileSets> +</assembly>
\ No newline at end of file diff --git a/champ-service/src/main/bin/start.sh b/champ-service/src/main/bin/start.sh new file mode 100644 index 0000000..de8a4fb --- /dev/null +++ b/champ-service/src/main/bin/start.sh @@ -0,0 +1,94 @@ +#!/bin/sh +# +# ============LICENSE_START========================================== +# org.onap.aai +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# Copyright © 2017 Amdocs +# =================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END============================================ +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +# + + +BASEDIR="/opt/app/champ-service/" +AJSC_HOME="$BASEDIR" +AJSC_CONF_HOME="$AJSC_HOME/bundleconfig/" + +if [ -z "$CONFIG_HOME" ]; then + echo "CONFIG_HOME must be set in order to start up process" + exit 1 +fi + +if [ -z "$KEY_STORE_PASSWORD" ]; then + echo "KEY_STORE_PASSWORD must be set in order to start up process" + exit 1 +else + echo "KEY_STORE_PASSWORD=$KEY_STORE_PASSWORD\n" >> $AJSC_CONF_HOME/etc/sysprops/sys-props.properties +fi + +if [ -z "$KEY_MANAGER_PASSWORD" ]; then + echo "KEY_MANAGER_PASSWORD must be set in order to start up process" + exit 1 +else + echo "KEY_MANAGER_PASSWORD=$KEY_MANAGER_PASSWORD\n" >> $AJSC_CONF_HOME/etc/sysprops/sys-props.properties +fi + +# Add any spring bean configuration files to the Gizmo deployment +if [ -n "$SERVICE_BEANS" ]; then + echo "Adding the following dynamic service beans to the deployment: " + mkdir -p /tmp/champ-service/v1/conf + for f in `ls $SERVICE_BEANS` + do + cp $SERVICE_BEANS/$f /tmp/champ-service/v1/conf + echo "Adding dynamic service bean $SERVICE_BEANS/$f" + done + jar uf /opt/app/champ-service/services/champ-service_v1.zip* -C /tmp/ champ-service + rm -rf /tmp/champ-service +fi + +CLASSPATH="$AJSC_HOME/lib/*" +CLASSPATH="$CLASSPATH:$AJSC_HOME/extJars/" +CLASSPATH="$CLASSPATH:$AJSC_HOME/etc/" + +# Check to see if the provided implementation exists in the image and add it to the classpath +for file in $( find ${BASEDIR}graph-deps/* -maxdepth 0 -type d ); do + CURRIMPL=$(echo $file | cut -d"/" -f6) + if [ "x$GRAPHIMPL" = "x$CURRIMPL" ]; then + CLASSPATH_GRAPHIMPL=$file + echo "Setting up graph implementation of $GRAPHIMPL" + else + SUPPORTED_GRAPHIMPL="$SUPPORTED_GRAPHIMPL $CURRIMPL" + fi +done +if [ -n "$CLASSPATH_GRAPHIMPL" ]; then + cp $CLASSPATH_GRAPHIMPL/* $AJSC_HOME/extJars/ +else + echo "Configured graph implementation '$GRAPHIMPL' is not supported. Acceptable implementations are one of: $SUPPORTED_GRAPHIMPL" + exit 1 +fi + +PROPS="-DAJSC_HOME=$AJSC_HOME" +PROPS="$PROPS -DAJSC_CONF_HOME=$BASEDIR/bundleconfig/" +PROPS="$PROPS -Dlogback.configurationFile=$BASEDIR/bundleconfig/etc/logback.xml" +PROPS="$PROPS -DAJSC_SHARED_CONFIG=$AJSC_CONF_HOME" +PROPS="$PROPS -DAJSC_SERVICE_NAMESPACE=champ-service" +PROPS="$PROPS -DAJSC_SERVICE_VERSION=v1" +PROPS="$PROPS -Dserver.port=9522" +PROPS="$PROPS -DCONFIG_HOME=$CONFIG_HOME" +JVM_MAX_HEAP=${MAX_HEAP:-1024} + +echo $CLASSPATH + +exec java -Xmx${JVM_MAX_HEAP}m $PROPS -classpath $CLASSPATH com.att.ajsc.runner.Runner context=// sslport=9522 diff --git a/champ-service/src/main/config/ajsc-chef.jks b/champ-service/src/main/config/ajsc-chef.jks Binary files differnew file mode 100644 index 0000000..aeca770 --- /dev/null +++ b/champ-service/src/main/config/ajsc-chef.jks diff --git a/champ-service/src/main/config/ajsc-jetty.xml b/champ-service/src/main/config/ajsc-jetty.xml new file mode 100644 index 0000000..98cc02e --- /dev/null +++ b/champ-service/src/main/config/ajsc-jetty.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> +<!-- Copyright (c) 2016 AT&T Intellectual Property. All rights reserved. --> +<Configure id="ajsc-server" class="org.eclipse.jetty.server.Server"> + <!-- DO NOT REMOVE!!!! This is setting up the AJSC Context --> + <New id="ajscContext" class="org.eclipse.jetty.webapp.WebAppContext"> + <Set name="contextPath"><SystemProperty name="AJSC_CONTEXT_PATH" /></Set> + <Set name="extractWAR">true</Set> + <Set name="tempDirectory"><SystemProperty name="AJSC_TEMP_DIR" /></Set> + <Set name="war"><SystemProperty name="AJSC_WAR_PATH" /></Set> + <Set name="descriptor"><SystemProperty name="AJSC_HOME" />/etc/runner-web.xml</Set> + <Set name="overrideDescriptor"><SystemProperty name="AJSC_HOME" />/etc/ajsc-override-web.xml</Set> + <Set name="throwUnavailableOnStartupException">true</Set> + <Set name="servletHandler"> + <New class="org.eclipse.jetty.servlet.ServletHandler"> + <Set name="startWithUnavailable">false</Set> + </New> + </Set> + <Set name="extraClasspath"><SystemProperty name="AJSC_HOME" />/extJars/champ-service.jar,<SystemProperty name="AJSC_HOME" />/extJars/json-20160212.jar,<SystemProperty name="AJSC_HOME" />/extJars/javax.ws.rs-api-2.0.1.jar,<SystemProperty name="AJSC_HOME" />/extJars/jersey-client-2.23.jar</Set> + </New> + + <Set name="handler"> + <New id="Contexts" + class="org.eclipse.jetty.server.handler.ContextHandlerCollection"> + <Set name="Handlers"> + <Array type="org.eclipse.jetty.webapp.WebAppContext"> + <Item> + <Ref refid="ajscContext" /> + </Item> + </Array> + </Set> + </New> + </Set> + + <Call name="addBean"> + <Arg> + <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> + <Set name="contexts"> + <Ref refid="Contexts" /> + </Set> + <Call id="extAppHotDeployProvider" name="addAppProvider"> + <Arg> + <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> + <Set name="monitoredDirName"><SystemProperty name="AJSC_HOME" />/extApps</Set> + <Set name="scanInterval">10</Set> + <Set name="extractWars">true</Set> + </New> + </Arg> + </Call> + </New> + </Arg> + </Call> + + <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> + <Set name="keyStorePath">file:<SystemProperty name="CONFIG_HOME" />/auth/tomcat_keystore</Set> + <Set name="KeyStorePassword"> + <Call class="org.eclipse.jetty.util.security.Password" name="deobfuscate"> + <Arg><SystemProperty name="KEY_STORE_PASSWORD" /></Arg> + </Call> + </Set> + <Set name="KeyManagerPassword"> + <Call class="org.eclipse.jetty.util.security.Password" name="deobfuscate"> + <Arg><SystemProperty name="KEY_MANAGER_PASSWORD" /></Arg> + </Call> + </Set> + <Set name="needClientAuth">true</Set> + <Set name="wantClientAuth">true</Set> + </New> + + <Call id="sslConnector" name="addConnector"> + <Arg> + <New class="org.eclipse.jetty.server.ServerConnector"> + <Arg name="server"> + <Ref refid="ajsc-server" /> + </Arg> + <Arg name="factories"> + <Array type="org.eclipse.jetty.server.ConnectionFactory"> + <Item> + <New class="org.eclipse.jetty.server.SslConnectionFactory"> + <Arg name="next">http/1.1</Arg> + <Arg name="sslContextFactory"> + <Ref refid="sslContextFactory" /> + </Arg> + </New> + </Item> + <Item> + <New class="org.eclipse.jetty.server.HttpConnectionFactory"> + <Arg name="config"> + <New class="org.eclipse.jetty.server.HttpConfiguration"> + <Call name="addCustomizer"> + <Arg> + <New class="org.eclipse.jetty.server.SecureRequestCustomizer" /> + </Arg> + </Call> + </New> + </Arg> + </New> + </Item> + </Array> + </Arg> + <Set name="port"><SystemProperty name="AJSC_HTTPS_PORT" default="9522" /></Set> + <Set name="idleTimeout">30000</Set> + </New> + </Arg> + </Call> + + <Get name="ThreadPool"> + <Set name="minThreads"><SystemProperty name="AJSC_JETTY_ThreadCount_MIN" /></Set> + <Set name="maxThreads"><SystemProperty name="AJSC_JETTY_ThreadCount_MAX" /></Set> + <Set name="idleTimeout"><SystemProperty name="AJSC_JETTY_IDLETIME_MAX" /></Set> + <Set name="detailedDump">false</Set> + </Get> + +</Configure> diff --git a/champ-service/src/main/config/ajsc-override-web.xml b/champ-service/src/main/config/ajsc-override-web.xml new file mode 100644 index 0000000..8e02d6d --- /dev/null +++ b/champ-service/src/main/config/ajsc-override-web.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + metadata-complete="false" version="3.0"> + + <filter-mapping> + <filter-name>InterceptorFilter</filter-name> + <url-pattern>/services/*</url-pattern> + </filter-mapping> + <filter-mapping> + <filter-name>InterceptorFilter</filter-name> + <url-pattern>/rest/*</url-pattern> + </filter-mapping> + + <filter-mapping> + <filter-name>springSecurityFilterChain</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <servlet-mapping> + <servlet-name>ManagementServlet</servlet-name> + <url-pattern>/mgmt</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>RestletServlet</servlet-name> + <url-pattern>/rest/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>CamelServlet</servlet-name> + <url-pattern>/services/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>jsp</servlet-name> + <url-pattern>*.jsp</url-pattern> + <url-pattern>*.jspf</url-pattern> + <url-pattern>*.jspx</url-pattern> + <url-pattern>*.xsp</url-pattern> + <url-pattern>*.JSP</url-pattern> + <url-pattern>*.JSPF</url-pattern> + <url-pattern>*.JSPX</url-pattern> + <url-pattern>*.XSP</url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name>default</servlet-name> + <url-pattern>/*</url-pattern> + </servlet-mapping> +</web-app>
\ No newline at end of file diff --git a/champ-service/src/main/config/ajscJetty.jks b/champ-service/src/main/config/ajscJetty.jks Binary files differnew file mode 100644 index 0000000..48cdbff --- /dev/null +++ b/champ-service/src/main/config/ajscJetty.jks diff --git a/champ-service/src/main/config/cadi.properties b/champ-service/src/main/config/cadi.properties new file mode 100644 index 0000000..cc527ed --- /dev/null +++ b/champ-service/src/main/config/cadi.properties @@ -0,0 +1,28 @@ +#This properties file is used for defining AAF properties related to the CADI framework. This file is used for running AAF framework +hostname=mywebserver.att.com + +#Setting csp_domain to PROD will allow for testing using your attuid and password through GLO. +csp_domain=PROD +csp_devl_localhost=true + +basic_realm=csp.att.com +#basic_realm=aaf.att.com +basic_warn=TRUE + +cadi_loglevel=WARN +cadi_keyfile=target/swm/package/nix/dist_files/appl/champ-service/etc/keyfile + +# Configure AAF +#These are dummy values add appropriate values required +aaf_url=url + +#AJSC - MECHID +#These are dummy values add appropriate values required +aaf_id=dummyid@ajsc.att.com +aaf_password=enc:277edqJCjT0RlUI3BtbDQa-3Ha-CQGd +aaf_timeout=5000 +aaf_clean_interval=30000 +aaf_user_expires=5000 +aaf_high_count=1000 + + diff --git a/champ-service/src/main/config/jul-redirect.properties b/champ-service/src/main/config/jul-redirect.properties new file mode 100644 index 0000000..8b6624d --- /dev/null +++ b/champ-service/src/main/config/jul-redirect.properties @@ -0,0 +1,13 @@ + +# Bridge JUL->slf4j Logging Configuration File +# +# This file bridges the JUL logging infrastructure into +# SLF4J so JUL logs go to logback implementation provided +# in this project. SLF4J also captures log4j and has +# other framework options as well providing a common +# logging infrastructure for capturing all logs from different +# libraries using different frameworks in one place. + +# Global properties +handlers=org.slf4j.bridge.SLF4JBridgeHandler +.level= ALL diff --git a/champ-service/src/main/config/keyfile b/champ-service/src/main/config/keyfile new file mode 100644 index 0000000..882e86a --- /dev/null +++ b/champ-service/src/main/config/keyfile @@ -0,0 +1,27 @@ +ZuIwp0TkyVPDeX1Up-8JtkMWvjsCpoiu1_VKeWrtrvxunvAke8_tiFyHPPyb2nkhepFYj6tXzpfS +rGz5XF_TH9NbsKaP8u0HV5clz2WriYQRvHS85vjY7hXxkpFuLb7zkLAPqTyIDpj7FiW61NzsRUAq +TM8jH16jr7mBNnb56w24mNGOwznMPcIZKcjgZU1ekaPDFpWyhQElU7Y0q_94P_Gkk45r66Hj22sU +OiOaaftmudZlswLw8-8Zaakqf2yW9HjMVfuYCwSodBHCW5rdB3Ctb5W36rnD_AQco3Ky2PgPmqvk +QkJYuUHpbuDqVHqLOajlKSIGMTIqAIBg51fRaaONtD-Q5xzY8E5wO1YWTLKcP5tsNvUpzM8Wu3NS +ynpGpUcvlTqWWsGzTbzOyamyKkdNdx97sSqjM25Zh1-ps48h6cddGYWpab7SUvqRCS11QBUyLTry +2iwTEHMhHRIbo7PO99ALQfuq9gI1zKGfurJdvLBeBaFs5SCF0AiCZ3WcDO8Rv3HpxVZ2_ShbDxb0 +eMoO6SotXu51fj8Y3-WqsfZziQyEsHyqpg5uQ6yUtz01h5YHLEoVuotF1U4agmQR6kEkYk-wNOiZ +v-8gaA9gtbLoAdKhuKFxQgQLNMf6GzVzZNujbmDzLoZAP_mXAv29aBPaf64Ugzv-Oa5GZdBgD-Xd +_pahML-ionw99r0TnkpShYmDqMKhMdjaP3m87WIAZkIB-L-VTyKcEsJ4340VSzCOsv3waiM0S89u +4cMcG5y-PLY8IoipIlLUPTWD3SjcQ9DV1Dt3T5KjdWLsj48D3W4K4e9PB8yxs0gtUjgVUR2_xEir +G5eDO9Ac1eHFWGDFFP0SgG-TbHJUKlvy9mwLzmU0fC3xPjhqmIr-v0HxF7HN-tmb1LHDorno8tSN +u7kUGcKSchIiFfvkd066crUb2mH7PnXTaWmAjyVj9VsBExFUYEdpHMAV4sAP9-RxZGDRt46UhrDK +QZvvNhBVyOEjHPHWI4vl1r1v8HNH1_2jZu5DVJWyHWR56aCo1lhFH9_X6UAHUHbnXViDONZOVXlT +9-WD0tk2zJGuwrhdZDAnPnAmjfwbwbpnr5Hmex1i1JiD7WVyP1kbfoej2TmdiYbxr9oBYaGQ29JI +aHod7MQCLtvL1z5XgnDPLZ4y3_9SbqHKYbNa8UgZkTLF5EacGThYVFDLA9cbafHDtR1kMGE3vv4D +EJ-0pAYTOGmKlVI7DwNyKsY9JTyudrxTqhOxi9jgcJNWiUaNe9yhL8Pyc2YBqUTTYhh_a2d1rvkZ +0Gh1crviVxqBrIkRKaMRXZ4f1vDLz-3NvG_vwPOo8WRFo5nGmSdTw7CjBaigJ_cYCfDhoP11pEnw +cndsZNcHs-v05LlxeIIMDD_f5Bvz-il_DLA4eK2HqgLdxh8ziSDl2azk14MJY4amzz6reEXUuKLV +RsZGf_jbDGKhE2HuDQ5ovoLOi4OqE1oRuqh-dGxitrYouP2SN1l_1tCEMRth86FMV-6AQtZsvdUo +y9MtQ7e35atjA8nHtgADlDTmJBKQiUHUsOZ77p1qp17HAFMovUkc739opfEYnKUn6Itpw5Ipm_Is +ra6chJUfMpOFof5rb5OjqFAN27c_-mPo1lQU3ndYlKGh_n5V8ufX6v2Yri8WzOPf6hjVYotkmoMP +NPAICDCB8W5ddBjsopzLVVEtaXDu9Qj6-zf77hT4iQ7rBd2Ner8iLqN3Kis0dvkNM3_uH8onau1G +Y_YYw7PPSZyd2S_7Dd6G-IG4ayO6e5DD6oUwwekyiQI_3rTXNa_wldGxqW9u818010ekE4Qdlfcj +beIn7fAeaOjReZ87hRgWyMs-EgTVHw8RL3yI_O6VvRTVRONRF1Y4C_-IYa8z-bfrwXx3BBd9TTgb +EnS9wVOyC2OgUN6BhPLGLhxzkJ05nEjizXEc9t5EPYoSRwesajGGrrG_0-qWbuU5hKLPLkyeJLHb +5HXOTVsrUR59Vov2M3_EswkxcImblox3k3VS2yihZMGyfqLzZIUXgd8ufkevKKU6DxwacGTb
\ No newline at end of file diff --git a/champ-service/src/main/config/runner-web.xml b/champ-service/src/main/config/runner-web.xml new file mode 100644 index 0000000..5f65183 --- /dev/null +++ b/champ-service/src/main/config/runner-web.xml @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + metadata-complete="false" version="3.0"> + + <context-param> + <param-name>contextConfigLocation</param-name> + <param-value>/WEB-INF/spring-servlet.xml, + classpath:applicationContext.xml + </param-value> + </context-param> + + <context-param> + <param-name>spring.profiles.default</param-name> + <param-value>nooauth</param-value> + </context-param> + + <listener> + <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> + </listener> + + <servlet> + <servlet-name>ManagementServlet</servlet-name> + <servlet-class>ajsc.ManagementServlet</servlet-class> + </servlet> + + + <filter> + <filter-name>InterceptorFilter</filter-name> + <filter-class>ajsc.filters.InterceptorFilter</filter-class> + <init-param> + <param-name>preProcessor_interceptor_config_file</param-name> + <param-value>/etc/PreProcessorInterceptors.properties</param-value> + </init-param> + <init-param> + <param-name>postProcessor_interceptor_config_file</param-name> + <param-value>/etc/PostProcessorInterceptors.properties</param-value> + </init-param> + + </filter> + + <servlet> + <servlet-name>RestletServlet</servlet-name> + <servlet-class>ajsc.restlet.RestletSpringServlet</servlet-class> + <init-param> + <param-name>org.restlet.component</param-name> + <param-value>restletComponent</param-value> + </init-param> + </servlet> + + <servlet> + <servlet-name>CamelServlet</servlet-name> + <servlet-class>ajsc.servlet.AjscCamelServlet</servlet-class> + </servlet> + + + <filter> + <filter-name>springSecurityFilterChain</filter-name> + <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> + </filter> + + <servlet> + <servlet-name>spring</servlet-name> + <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> + <load-on-startup>1</load-on-startup> + </servlet> + +<!-- <servlet-mapping> + <servlet-name>spring</servlet-name> + <url-pattern>/</url-pattern> + </servlet-mapping>--> + +<!-- BEGIN jsp --> + + <servlet id="jsp"> + <servlet-name>jsp</servlet-name> + <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> + </servlet> + + + + + + <!-- BEGIN static content --> + <servlet> + <servlet-name>default</servlet-name> + <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class> + <init-param> + <param-name>dirAllowed</param-name> + <param-value>true</param-value> + </init-param> + </servlet> + <!-- END static content --> +</web-app> diff --git a/champ-service/src/main/docker/Dockerfile b/champ-service/src/main/docker/Dockerfile new file mode 100644 index 0000000..cf299a2 --- /dev/null +++ b/champ-service/src/main/docker/Dockerfile @@ -0,0 +1,34 @@ +FROM ubuntu:14.04 + +ARG MICRO_HOME=/opt/app/champ-service +ARG BIN_HOME=$MICRO_HOME/bin +ARG GRAPHLIB_HOME=$MICRO_HOME/graph-deps + +RUN apt-get update + +# Install and setup java8 +RUN apt-get update && apt-get install -y software-properties-common +RUN sudo -E add-apt-repository ppa:openjdk-r/ppa && apt-get update && apt-get install -y openjdk-8-jdk +ENV JAVA_HOME usr/lib/jvm/java-8-openjdk-amd64 +RUN export JAVA_HOME + +# Build up the deployment folder structure +RUN mkdir -p $MICRO_HOME +ADD swm/package/nix/dist_files/appl/champ-service/* $MICRO_HOME/ +RUN mkdir -p $GRAPHLIB_HOME +ADD graph-deps $GRAPHLIB_HOME +RUN mkdir -p $BIN_HOME +COPY *.sh $BIN_HOME +RUN chmod 755 $BIN_HOME/* +RUN ln -s /logs $MICRO_HOME/logs + +# Create the aai user +RUN mkdir /opt/aaihome && \ + groupadd -g 492381 aaiadmin && \ + useradd -r -u 341790 -g 492381 -ms /bin/bash -d /opt/aaihome/aaiadmin aaiadmin && \ + chown -R aaiadmin:aaiadmin $MICRO_HOME +USER aaiadmin + +EXPOSE 9522 9522 + +CMD ["/opt/app/champ-service/bin/start.sh"] diff --git a/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java b/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java new file mode 100644 index 0000000..3d7e074 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java @@ -0,0 +1,568 @@ +package org.onap.champ; + +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Timer; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.json.JSONException; +import org.json.JSONObject; +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException; +import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException; +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.ChampRelationship; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.async.ChampAsyncRequestProcessor; +import org.onap.champ.entity.ChampObjectDeserializer; +import org.onap.champ.entity.ChampObjectSerializer; +import org.onap.champ.entity.ChampRelationshipDeserializer; +import org.onap.champ.entity.ChampRelationshipSerializer; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.service.ChampDataService; +import org.onap.champ.service.logging.ChampMsgs; +import org.onap.champ.service.logging.LoggingUtil; +import org.onap.champ.util.ChampProperties; +import org.onap.champ.util.ChampServiceConstants; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +@Path(value = "/") +public class ChampRESTAPI { + + private ObjectMapper mapper; + + private ChampDataService champDataService; + private String TRANSACTION_METHOD = "method"; + private Timer timer; + + private Logger logger = LoggerFactory.getInstance().getLogger(ChampRESTAPI.class); + Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(ChampRESTAPI.class.getName()); + private static Logger metricsLogger = LoggerFactory.getInstance().getMetricsLogger(ChampRESTAPI.class.getName()); + + public ChampRESTAPI(ChampDataService champDataService, ChampAsyncRequestProcessor champAsyncRequestProcessor) { + this.champDataService = champDataService; + + // Async request handling is optional. + if (champAsyncRequestProcessor != null) { + timer = new Timer("ChampAsyncRequestProcessor-1"); + timer.schedule(champAsyncRequestProcessor, champAsyncRequestProcessor.getRequestPollingTimeSeconds(), + champAsyncRequestProcessor.getRequestPollingTimeSeconds()); + } + + mapper = new ObjectMapper(); + SimpleModule module = new SimpleModule(); + module.addSerializer(ChampObject.class, new ChampObjectSerializer()); + module.addDeserializer(ChampObject.class, new ChampObjectDeserializer()); + module.addSerializer(ChampRelationship.class, new ChampRelationshipSerializer()); + module.addDeserializer(ChampRelationship.class, new ChampRelationshipDeserializer()); + mapper.registerModule(module); + } + + @GET + @Path("echo") + @Produces(MediaType.TEXT_PLAIN) + public Response echo() { + return Response.ok().entity("alive").build(); + } + + @GET + @Path("objects/{objectId}") + @Produces(MediaType.APPLICATION_JSON) + public Response getObject(@PathParam("objectId") String objectId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId); + + Response response = null; + ChampObject retrieved; + + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + retrieved = champDataService.getObject(objectId, Optional.ofNullable(transaction)); + if (retrieved == null) { + response = Response.status(Status.NOT_FOUND).entity(objectId + " not found").build(); + } else { + response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).build(); + } + + } catch (JsonProcessingException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } finally { + logger.debug(response.getEntity().toString()); + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + + return response; + } + + @DELETE + @Path("objects/{objectId}") + public Response deleteObject(@PathParam("objectId") String objectId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId); + ChampObject retrieved; + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + champDataService.deleteObject(objectId, Optional.ofNullable(transaction)); + + response = Response.status(Status.OK).build(); + } catch (ChampObjectNotExistsException e) { + response = Response.status(Status.NOT_FOUND).entity(objectId + " not found").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (ChampTransactionException | ChampUnmarshallingException e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @POST + @Path("objects") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response postObject(String champObj, @QueryParam("transactionId") String tId, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, champObj); + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + ChampObject champObject = mapper.readValue(champObj, ChampObject.class); + + ChampObject created = champDataService.storeObject(champObject, Optional.ofNullable(transaction)); + response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @PUT + @Path("objects/{objectId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response putObject(@PathParam("objectId") String objectId, String champObj, + @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId + " " + champObj); + + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + + ChampObject co = mapper.readValue(champObj, ChampObject.class); + // check if key is present or if it equals the key that is in the URI + ChampObject updated = champDataService.replaceObject(co, objectId, Optional.ofNullable(transaction)); + + response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("objects/relationships/{oId}") + @Produces(MediaType.APPLICATION_JSON) + public Response getEdges(@PathParam("oId") String oId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + List<ChampRelationship> retrieved; + Optional<ChampObject> rObject; + Response response = null; + ChampTransaction transaction = null; + try { + + retrieved = champDataService.getRelationshipsByObject(oId, Optional.ofNullable(transaction)); + response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).build(); + } catch (JsonProcessingException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("objects/filter/") + @Produces(MediaType.APPLICATION_JSON) + public Response filterObject(@Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + String propertiesKey = ChampProperties.get(ChampServiceConstants.CHAMP_COLLECTION_PROPERTIES_KEY); + List<ChampObject> objects; + Map<String, Object> filter = new HashMap<>(); + + for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) { + if (!e.getKey().equals(propertiesKey)) { + filter.put(e.getKey(), e.getValue().get(0)); + } + } + + HashSet<String> properties; + if (uriInfo.getQueryParameters().containsKey(propertiesKey)) { + properties = new HashSet<>(uriInfo.getQueryParameters().get(propertiesKey)); + } else { + properties = new HashSet<>(); + } + + Response response = null; + try { + objects = champDataService.queryObjects(filter, properties); + response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(mapper.writeValueAsString(objects)) + .build(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException e1) { + response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("relationships/{rId}") + @Produces(MediaType.APPLICATION_JSON) + public Response getRelationship(@PathParam("rId") String rId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, rId); + ChampRelationship retrieved; + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + retrieved = champDataService.getRelationship(rId, Optional.ofNullable(transaction)); + if (retrieved == null) { + response = Response.status(Status.NOT_FOUND).entity(rId + " not found").build(); + return response; + } + response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).build(); + + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @POST + @Path("relationships") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response postRelationships(String relationship, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship); + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class); + + ChampRelationship created = champDataService.storeRelationship(r, Optional.ofNullable(transaction)); + + response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @PUT + @Path("relationships/{rId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updateRelationship(@PathParam("rId") String rId, String relationship, + @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship); + + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class); + ChampRelationship updated = champDataService.updateRelationship(r, rId, Optional.ofNullable(transaction)); + + response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @DELETE + @Path("relationships/{relationshipId}") + public Response deleteRelationship(@PathParam("relationshipId") String relationshipId, + @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationshipId); + + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + champDataService.deleteRelationship(relationshipId, Optional.ofNullable(transaction)); + response = Response.status(Status.OK).build(); + + } catch (ChampRelationshipNotExistsException e) { + response = Response.status(Status.NOT_FOUND).entity(relationshipId + " not found").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (ChampTransactionException | ChampUnmarshallingException e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("relationships/filter/") + @Produces(MediaType.APPLICATION_JSON) + public Response filterMethod(@Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + List<ChampRelationship> list; + Map<String, Object> filter = new HashMap<>(); + for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) { + filter.put(e.getKey(), e.getValue().get(0)); + } + Response response = null; + try { + list = champDataService.queryRelationships(filter); + response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(mapper.writeValueAsString(list)) + .build(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException e1) { + response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @POST + @Path("transaction") + @Produces(MediaType.TEXT_PLAIN) + public Response openTransaction(@Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + Status s; + String transaction = champDataService.openTransaction(); + + s = Status.OK; + Response response = Response.status(s).entity(transaction).build(); + logger.info(ChampMsgs.PROCESS_EVENT, "Opened Transaction with ID: " + transaction, s.toString()); + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", Long.toString(System.currentTimeMillis() - startTimeInMs)); + return response; + } + + @GET + @Path("transaction/{tId}") + public Response getSpecificTransaction(@PathParam("tId") String tId, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + + Response response = null; + ChampTransaction transaction = champDataService.getTransaction(tId); + if (transaction == null) { + response = Response.status(Status.NOT_FOUND).entity("transaction " + tId + " not found").build(); + return response; + } + + try { + response = Response.status(Status.OK).entity(mapper.writeValueAsString(tId + " is OPEN")).build(); + } catch (JsonProcessingException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @PUT + @Path("transaction/{tId}") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_JSON) + public Response updateTransaction(String t, @PathParam("tId") String tId, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, "COMMIT/ROLLBACK"); + + Response response = null; + try { + JSONObject jsonObj = new JSONObject(t); + String method = jsonObj.getString(this.TRANSACTION_METHOD); + + if (method.equals("commit")) { + champDataService.commitTransaction(tId); + response = Response.status(Status.OK).entity("COMMITTED").build(); + + } else if (method.equals("rollback")) { + champDataService.rollbackTransaction(tId); + response = Response.status(Status.OK).entity("ROLLED BACK").build(); + } else { + response = Response.status(Status.BAD_REQUEST).entity("Invalid Method: " + method).build(); + return response; + } + + } catch (ChampTransactionException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (JSONException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException e) { + response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/async/ChampAsyncRequestProcessor.java b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncRequestProcessor.java new file mode 100644 index 0000000..af2ab20 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncRequestProcessor.java @@ -0,0 +1,327 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.async; + +import java.util.Optional; +import java.util.TimerTask; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +import javax.naming.OperationNotSupportedException; +import javax.ws.rs.core.Response.Status; + +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.ChampRESTAPI; +import org.onap.champ.event.GraphEvent; +import org.onap.champ.event.GraphEvent.GraphEventResult; +import org.onap.champ.event.GraphEventEdge; +import org.onap.champ.event.GraphEventVertex; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.service.ChampDataService; +import org.onap.champ.service.ChampThreadFactory; +import org.onap.champ.service.logging.ChampMsgs; + +import org.onap.aai.event.api.EventConsumer; + +/** + * This Class polls the Graph events from request topic perform the necessary + * CRUD operation by calling champDAO and queues up the response to be consumed + * by response handler. + */ +public class ChampAsyncRequestProcessor extends TimerTask { + + private Logger logger = LoggerFactory.getInstance().getLogger(ChampAsyncRequestProcessor.class); + + private ChampDataService champDataService; + + /** + * Number of events that can be queued up. + */ + private Integer requestProcesserQueueSize; + + /** + * Number of event publisher worker threads. + */ + private Integer requestProcesserPoolSize; + + /** + * Number of event publisher worker threads. + */ + private Integer requestPollingTimeSeconds; + + /** + * Internal queue where outgoing events will be buffered until they can be + * serviced by. + **/ + private BlockingQueue<GraphEvent> requestProcesserEventQueue; + + /** + * Pool of worker threads that do the work of publishing the events to the + * event bus. + */ + private ThreadPoolExecutor requestProcesserPool; + + private ChampAsyncResponsePublisher champAsyncResponsePublisher; + + private EventConsumer asyncRequestConsumer; + + private static final Integer DEFAULT_ASYNC_REQUEST_PROCESS_QUEUE_CAPACITY = 10000; + + private static final Integer DEFAULT_ASYNC_REQUEST_PROCESS_THREAD_POOL_SIZE = 10; + private static final Integer DEFAULT_ASYNC_REQUEST_PROCESS_POLLING_SECOND = 30000; + private static final String CHAMP_GRAPH_REQUEST_PROCESS_THREAD_NAME = "ChampAsyncGraphRequestEventProcessor"; + Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(ChampRESTAPI.class.getName()); + + public ChampAsyncRequestProcessor(ChampDataService champDataService, + ChampAsyncResponsePublisher champAsyncResponsePublisher, EventConsumer asyncRequestConsumer) { + + this.requestProcesserQueueSize = DEFAULT_ASYNC_REQUEST_PROCESS_QUEUE_CAPACITY; + + this.requestProcesserPoolSize = DEFAULT_ASYNC_REQUEST_PROCESS_THREAD_POOL_SIZE; + + this.requestPollingTimeSeconds = DEFAULT_ASYNC_REQUEST_PROCESS_POLLING_SECOND; + requestProcesserEventQueue = new ArrayBlockingQueue<GraphEvent>(requestProcesserQueueSize); + requestProcesserPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(requestProcesserPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_REQUEST_PROCESS_THREAD_NAME)); + + for (int i = 0; i < requestProcesserPoolSize; i++) { + requestProcesserPool.submit(new ChampProcessorWorker()); + } + + this.champDataService = champDataService; + this.champAsyncResponsePublisher = champAsyncResponsePublisher; + this.asyncRequestConsumer = asyncRequestConsumer; + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "ChampAsyncRequestProcessor initialized SUCCESSFULLY! with event consumer " + + asyncRequestConsumer.getClass().getName()); + } + + + + public ChampAsyncRequestProcessor(ChampDataService champDataService, + ChampAsyncResponsePublisher champAsyncResponsePublisher, EventConsumer asyncRequestConsumer, + Integer requestProcesserQueueSize, Integer requestProcesserPoolSize, Integer requestPollingTimeSeconds) { + + this.requestProcesserQueueSize = requestProcesserQueueSize; + + this.requestProcesserPoolSize = requestProcesserPoolSize; + + this.requestPollingTimeSeconds = requestPollingTimeSeconds; + + requestProcesserEventQueue = new ArrayBlockingQueue<GraphEvent>(requestProcesserQueueSize); + requestProcesserPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(requestProcesserPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_REQUEST_PROCESS_THREAD_NAME)); + + for (int i = 0; i < requestProcesserPoolSize; i++) { + requestProcesserPool.submit(new ChampProcessorWorker()); + } + + this.champDataService = champDataService; + this.champAsyncResponsePublisher = champAsyncResponsePublisher; + this.asyncRequestConsumer = asyncRequestConsumer; + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "ChampAsyncRequestProcessor initialized SUCCESSFULLY! with event consumer " + + asyncRequestConsumer.getClass().getName()); + } + + private class ChampProcessorWorker implements Runnable { + + @Override + public void run() { + + while (true) { + + GraphEvent event = null; + try { + // Get the next event to be published from the queue. + event = requestProcesserEventQueue.take(); + } catch (InterruptedException e) { + // Restore the interrupted status. + Thread.currentThread().interrupt(); + } + + // Parse the event and call champ Dao to process , Create the + // response event and put it on response queue + event.setResult(GraphEventResult.SUCCESS); + + // Check if this request is part of an ongoing DB transaction + ChampTransaction transaction = champDataService.getTransaction(event.getDbTransactionId()); + if ( (event.getDbTransactionId() != null) && (transaction == null) ) { + event.setResult(GraphEventResult.FAILURE); + event.setErrorMessage("Database transactionId " + event.getDbTransactionId() + " not found"); + event.setHttpErrorStatus(Status.BAD_REQUEST); + } + + if (event.getResult() != GraphEventResult.FAILURE) { + try { + if (event.getVertex() != null) { + + switch (event.getOperation()) { + case CREATE: + event.setVertex(GraphEventVertex.fromChampObject( + champDataService.storeObject(event.getVertex().toChampObject(), Optional.ofNullable(transaction)), + event.getVertex().getModelVersion())); + break; + + case UPDATE: + event.setVertex(GraphEventVertex.fromChampObject( + champDataService.replaceObject(event.getVertex().toChampObject(), event.getVertex().getId(), Optional.ofNullable(transaction)), + event.getVertex().getModelVersion())); + break; + case DELETE: + champDataService.deleteObject(event.getVertex().getId(), Optional.ofNullable(transaction)); + break; + default: + // log error + } + } else if (event.getEdge() != null) { + switch (event.getOperation()) { + case CREATE: + event.setEdge(GraphEventEdge.fromChampRelationship( + champDataService.storeRelationship(event.getEdge().toChampRelationship(), Optional.ofNullable(transaction)), + event.getEdge().getModelVersion())); + break; + + case UPDATE: + event.setEdge(GraphEventEdge.fromChampRelationship(champDataService + .updateRelationship(event.getEdge().toChampRelationship(), event.getEdge().getId(), Optional.ofNullable(transaction)), + event.getEdge().getModelVersion())); + + break; + case DELETE: + champDataService.deleteRelationship(event.getEdge().getId(), Optional.ofNullable(transaction)); + break; + default: + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + "Invalid operation for event transactionId: " + event.getTransactionId()); + } + + } else { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + "Invalid payload for event transactionId: " + event.getTransactionId()); + } + } catch (ChampServiceException champException) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, champException.getMessage()); + event.setResult(GraphEventResult.FAILURE); + event.setErrorMessage(champException.getMessage()); + event.setHttpErrorStatus(champException.getHttpStatus()); + + } catch (Exception ex) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, ex.getMessage()); + event.setResult(GraphEventResult.FAILURE); + event.setErrorMessage(ex.getMessage()); + event.setHttpErrorStatus(Status.INTERNAL_SERVER_ERROR); + } + } + + if (event.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event processed of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult()); + } else { + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event processed of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult() + " , error: " + + event.getErrorMessage()); + } + + champAsyncResponsePublisher.publishResponseEvent(event); + + } + } + } + + @Override + public void run() { + + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, "Listening for graph events"); + + if (asyncRequestConsumer == null) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, "Unable to initialize ChampAsyncRequestProcessor"); + } + + Iterable<String> events = null; + try { + events = asyncRequestConsumer.consume(); + } catch (Exception e) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, e.getMessage()); + return; + } + + if (events == null || !events.iterator().hasNext()) { + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, "No events recieved"); + + } + + for (String event : events) { + try { + GraphEvent requestEvent = GraphEvent.fromJson(event); + auditLogger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event received of type: " + requestEvent.getObjectType() + " with key: " + requestEvent.getObjectKey() + + " , transaction-id: " + requestEvent.getTransactionId() + " , operation: " + + requestEvent.getOperation().toString()); + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event received of type: " + requestEvent.getObjectType() + " with key: " + requestEvent.getObjectKey() + + " , transaction-id: " + requestEvent.getTransactionId() + " , operation: " + + requestEvent.getOperation().toString()); + logger.debug(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, "Event received with payload:" + event); + + // Try to submit the event to be published to the event bus. + if (!requestProcesserEventQueue.offer(requestEvent)) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + "Event could not be published to the event bus due to: Internal buffer capacity exceeded."); + } + + } catch (Exception e) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, e.getMessage()); + } + } + + try { + asyncRequestConsumer.commitOffsets(); + } catch(OperationNotSupportedException e) { + //Dmaap doesnt support commit with offset + logger.debug(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_WARN, e.getMessage()); + } + catch (Exception e) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_WARN, e.getMessage()); + } + + } + + + + public Integer getRequestPollingTimeSeconds() { + return requestPollingTimeSeconds; + } + + +} diff --git a/champ-service/src/main/java/org/onap/champ/async/ChampAsyncResponsePublisher.java b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncResponsePublisher.java new file mode 100644 index 0000000..8c31a53 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncResponsePublisher.java @@ -0,0 +1,160 @@ +/** + * ============LICENSE_START======================================================= + * + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.async; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.event.GraphEvent; +import org.onap.champ.event.GraphEvent.GraphEventResult; +import org.onap.champ.service.ChampThreadFactory; +import org.onap.champ.service.logging.ChampMsgs; + +import org.onap.aai.event.api.EventPublisher; + +public class ChampAsyncResponsePublisher { + + private EventPublisher asyncResponsePublisher; + + /** + * Number of events that can be queued up. + */ + private Integer responsePublisherQueueSize; + + /** + * Number of event publisher worker threads. + */ + private Integer responsePublisherPoolSize; + + /** + * Internal queue where outgoing events will be buffered. + **/ + private BlockingQueue<GraphEvent> responsePublisherEventQueue; + + /** + * Pool of worker threads that do the work of publishing the events to the + * event bus. + */ + private ThreadPoolExecutor responsePublisherPool; + + private static final Integer DEFAULT_ASYNC_RESPONSE_PUBLISH_QUEUE_CAPACITY = 10000; + + private static final Integer DEFAULT_ASYNC_RESPONSE_PUBLISH_THREAD_POOL_SIZE = 10; + private static final String CHAMP_GRAPH_RESPONSE_PUBLISH_THREAD_NAME = "ChampAsyncGraphResponseEventPublisher"; + + private static Logger logger = LoggerFactory.getInstance().getLogger(ChampAsyncRequestProcessor.class.getName()); + + public ChampAsyncResponsePublisher(EventPublisher asyncResponsePublisher, Integer responsePublisherQueueSize, + Integer responsePublisherPoolSize) { + this.responsePublisherQueueSize = responsePublisherQueueSize; + + this.responsePublisherPoolSize = responsePublisherPoolSize; + + responsePublisherEventQueue = new ArrayBlockingQueue<GraphEvent>(responsePublisherQueueSize); + responsePublisherPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(responsePublisherPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_RESPONSE_PUBLISH_THREAD_NAME)); + + for (int i = 0; i < responsePublisherPoolSize; i++) { + responsePublisherPool.submit(new GizmoResponsePublisherWorker()); + } + this.asyncResponsePublisher = asyncResponsePublisher; + + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "ChampAsyncResponsePublisher initialized SUCCESSFULLY! with event publisher " + + asyncResponsePublisher.getClass().getName()); + } + + public ChampAsyncResponsePublisher(EventPublisher asyncResponsePublisher) { + responsePublisherQueueSize = DEFAULT_ASYNC_RESPONSE_PUBLISH_QUEUE_CAPACITY; + + responsePublisherPoolSize = DEFAULT_ASYNC_RESPONSE_PUBLISH_THREAD_POOL_SIZE; + + responsePublisherEventQueue = new ArrayBlockingQueue<GraphEvent>(responsePublisherQueueSize); + responsePublisherPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(responsePublisherPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_RESPONSE_PUBLISH_THREAD_NAME)); + + for (int i = 0; i < responsePublisherPoolSize; i++) { + responsePublisherPool.submit(new GizmoResponsePublisherWorker()); + } + this.asyncResponsePublisher = asyncResponsePublisher; + + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "CrudAsyncResponsePublisher initialized SUCCESSFULLY! with event publisher " + + asyncResponsePublisher.getClass().getName()); + } + + public void publishResponseEvent(GraphEvent event) { + responsePublisherEventQueue.offer(event); + + } + + private class GizmoResponsePublisherWorker implements Runnable { + + @Override + public void run() { + + while (true) { + + GraphEvent event = null; + try { + + // Get the next event to be published from the queue. + event = responsePublisherEventQueue.take(); + + } catch (InterruptedException e) { + + // Restore the interrupted status. + Thread.currentThread().interrupt(); + } + // Publish the response + + try { + event.setTimestamp(System.currentTimeMillis()); + asyncResponsePublisher.sendSync(event.toJson()); + if (event.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "Response published for Event of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult()); + } else { + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "Response published for Event of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult() + " , error: " + + event.getErrorMessage()); + } + } catch (Exception ex) { + logger.error(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_ERROR, ex.getMessage()); + } + + } + } + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampObjectDeserializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectDeserializer.java new file mode 100644 index 0000000..cee7763 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectDeserializer.java @@ -0,0 +1,67 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.champ.entity; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.onap.aai.champcore.model.ChampObject; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +public class ChampObjectDeserializer extends StdDeserializer<ChampObject> { + + private static final long serialVersionUID = -3625275249560680339L; + + public ChampObjectDeserializer() { + this(null); + } + + protected ChampObjectDeserializer(Class<ChampObject> t) { + super(t); + } + + public ChampObject deserialize(JsonParser jparser, DeserializationContext dctx) + throws IOException, JsonProcessingException { + + JsonNode node = jparser.getCodec().readTree(jparser); + JsonNode type = node.get("type"); + JsonNode key = node.get("key"); + Map<String, Object> props = new HashMap<>(); + JsonNode propNode = node.get("properties"); + propNode.fields().forEachRemaining((x)->props.put(x.getKey(), x.getValue().asText())); + + ChampObject.Builder builder = new ChampObject.Builder(type.asText()).properties(props); + + if(key != null){ + builder.key(key.asText()); + } + + return builder.build(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampObjectSerializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectSerializer.java new file mode 100644 index 0000000..c43b6bf --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectSerializer.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.champ.entity; + +import java.io.IOException; + +import org.onap.aai.champcore.model.ChampObject; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +public class ChampObjectSerializer extends StdSerializer<ChampObject> { + + private static final long serialVersionUID = -4057960968983473983L; + + public ChampObjectSerializer() { + this(null); + } + + protected ChampObjectSerializer(Class<ChampObject> t) { + super(t); + } + + public void serialize(ChampObject co, JsonGenerator jgen, SerializerProvider ser) + throws IOException, JsonGenerationException { + jgen.writeStartObject(); + jgen.writeStringField("key", co.getKeyValue().toString()); + jgen.writeStringField("type", co.getType()); + jgen.writeObjectField("properties", co.getProperties()); + jgen.writeEndObject(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipDeserializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipDeserializer.java new file mode 100644 index 0000000..63b9e0c --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipDeserializer.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.champ.entity; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; + +public class ChampRelationshipDeserializer extends StdDeserializer<ChampRelationship> { + + private static final long serialVersionUID = -3625275249560680339L; + + public ChampRelationshipDeserializer() { + this(null); + } + + protected ChampRelationshipDeserializer(Class<ChampRelationship> t) { + super(t); + } + + public ChampRelationship deserialize(JsonParser jparser, DeserializationContext dctx) + throws IOException, JsonProcessingException { + + JsonNode node = jparser.getCodec().readTree(jparser); + JsonNode type = node.get("type"); + JsonNode key = node.get("key"); + Map<String, Object> props = new HashMap<>(); + JsonNode propNode = node.get("properties"); + propNode.fields().forEachRemaining((x)->props.put(x.getKey(), x.getValue().asText())); + + JsonNode srcNode = node.get("source"); + JsonNode targetNode = node.get("target"); + + ChampObject src = jparser.getCodec ().treeToValue ( srcNode, ChampObject.class ); + ChampObject target = jparser.getCodec ().treeToValue ( targetNode, ChampObject.class ); + + ChampRelationship.Builder builder = new ChampRelationship.Builder(src, target, type.asText()).properties(props); + + if(key != null){ + builder.key(key.asText()); + } + + return builder.build(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipSerializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipSerializer.java new file mode 100644 index 0000000..5d21aa5 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipSerializer.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.champ.entity; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.onap.aai.champcore.model.ChampRelationship; + +import java.io.IOException; + +public class ChampRelationshipSerializer extends StdSerializer<ChampRelationship> { + + private static final long serialVersionUID = -4057960968983473983L; + + public ChampRelationshipSerializer() { + this(null); + } + + protected ChampRelationshipSerializer(Class<ChampRelationship> t) { + super(t); + } + + public void serialize( ChampRelationship cr, JsonGenerator jgen, SerializerProvider ser) + throws IOException, JsonGenerationException { + jgen.writeStartObject(); + jgen.writeStringField("key", cr.getKeyValue().toString()); + jgen.writeStringField("type", cr.getType()); + jgen.writeObjectField("properties", cr.getProperties()); + jgen.writeObjectField ("source", cr.getSource()); + jgen.writeObjectField ("target", cr.getTarget ()); + jgen.writeEndObject(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/event/GraphEvent.java b/champ-service/src/main/java/org/onap/champ/event/GraphEvent.java new file mode 100644 index 0000000..d649a3e --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/event/GraphEvent.java @@ -0,0 +1,245 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.event; + +import javax.ws.rs.core.Response.Status; + +import org.onap.champ.exception.ChampServiceException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; + +public class GraphEvent { + + public enum GraphEventOperation { + CREATE, UPDATE, DELETE + } + + public enum GraphEventResult { + SUCCESS, FAILURE + } + + private GraphEventOperation operation; + + @SerializedName("transaction-id") + private String transactionId; + + @SerializedName("database-transaction-id") + private String dbTransactionId; + + private long timestamp; + + private GraphEventVertex vertex; + + private GraphEventEdge edge; + + private GraphEventResult result; + + @SerializedName("error-message") + private String errorMessage; + + private Status httpErrorStatus; + + /** + * Marshaller/unmarshaller for converting to/from JSON. + */ + private static final Gson gson = new GsonBuilder().disableHtmlEscaping() + .setPrettyPrinting().create(); + + public static Builder builder(GraphEventOperation operation) { + return new Builder(operation); + } + + public GraphEventOperation getOperation() { + return operation; + } + + public String getTransactionId() { + return transactionId; + } + + public String getDbTransactionId() { + return dbTransactionId; + } + + public void setDbTransactionId(String id) { + dbTransactionId = id; + } + + public long getTimestamp() { + return timestamp; + } + + public GraphEventVertex getVertex() { + return vertex; + } + + public GraphEventEdge getEdge() { + return edge; + } + + public GraphEventResult getResult() { + return result; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setResult(GraphEventResult result) { + this.result = result; + } + + + public Status getHttpErrorStatus() { + return httpErrorStatus; + } + + public void setHttpErrorStatus(Status httpErrorStatus) { + this.httpErrorStatus = httpErrorStatus; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public void setVertex(GraphEventVertex vertex) { + this.vertex = vertex; + } + + public void setEdge(GraphEventEdge edge) { + this.edge = edge; + } + + /** + * Unmarshalls this Vertex object into a JSON string. + * + * @return - A JSON format string representation of this Vertex. + */ + public String toJson() { + return gson.toJson(this); + } + + /** + * Marshalls the provided JSON string into a Vertex object. + * + * @param json - The JSON string to produce the Vertex from. + * @return - A Vertex object. + * @throws SpikeException + */ + public static GraphEvent fromJson(String json) throws ChampServiceException { + + try { + + // Make sure that we were actually provided a non-empty string + // before we + // go any further. + if (json == null || json.isEmpty()) { + throw new ChampServiceException("Empty or null JSON string.", Status.BAD_REQUEST); + } + + // Marshall the string into a Vertex object. + return gson.fromJson(json, GraphEvent.class); + + } catch (Exception ex) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + } + + @Override + public String toString() { + + return toJson(); + } + + public String getObjectKey() { + if (this.getVertex() != null) { + return this.getVertex().getId(); + } else if (this.getEdge() != null) { + return this.getEdge().getId(); + } + + return null; + } + + public String getObjectType() { + if (this.getVertex() != null) { + return "vertex->" + this.getVertex().getType(); + } else if (this.getEdge() != null) { + return "edge->" + this.getEdge().getType(); + } + + return null; + } + + public static class Builder { + + GraphEvent event = null; + + public Builder(GraphEventOperation operation) { + event = new GraphEvent(); + event.operation = operation; + } + + public Builder vertex(GraphEventVertex vertex) { + event.vertex = vertex; + return this; + } + + public Builder edge(GraphEventEdge edge) { + event.edge = edge; + return this; + } + + public Builder result(GraphEventResult result) { + event.result = result; + return this; + } + + public Builder errorMessage(String errorMessage) { + event.errorMessage = errorMessage; + return this; + } + + public Builder httpErrorStatus(Status httpErrorStatus) { + event.httpErrorStatus = httpErrorStatus; + return this; + } + + public GraphEvent build() { + + event.timestamp = System.currentTimeMillis(); + event.transactionId = java.util.UUID.randomUUID().toString(); + + return event; + } + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/event/GraphEventEdge.java b/champ-service/src/main/java/org/onap/champ/event/GraphEventEdge.java new file mode 100644 index 0000000..1ab4804 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/event/GraphEventEdge.java @@ -0,0 +1,221 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.event; + +import java.util.Map; + +import javax.ws.rs.core.Response.Status; + +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.champ.exception.ChampServiceException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +/** + * This class provides a generic representation of an Edge as provided by the + * graph data store. + */ +public class GraphEventEdge { + + /** + * The unique identifier used to identify this edge in the graph data store. + */ + @SerializedName("key") + private String id; + + @SerializedName("schema-version") + private String modelVersion; + + /** + * Type label assigned to this vertex. + */ + private String type; + + /** + * Source vertex for our edge. + */ + private GraphEventVertex source; + + /** + * Target vertex for our edge. + */ + private GraphEventVertex target; + + /** + * Map of all of the properties assigned to this vertex. + */ + private JsonElement properties; + + /** + * Marshaller/unmarshaller for converting to/from JSON. + */ + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + + public GraphEventEdge(String id, String modelVersion, String type, GraphEventVertex source, + GraphEventVertex target, JsonElement properties) { + this.id = id; + this.modelVersion = modelVersion; + this.type = type; + this.source = source; + this.target = target; + this.properties = properties; + } + + public GraphEventEdge() { + + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public GraphEventVertex getSource() { + return source; + } + + public void setSource(GraphEventVertex source) { + this.source = source; + } + + public GraphEventVertex getTarget() { + return target; + } + + public void setTarget(GraphEventVertex target) { + this.target = target; + } + + public JsonElement getProperties() { + return properties; + } + + public void setProperties(JsonElement properties) { + this.properties = properties; + } + + public String getModelVersion() { + return modelVersion; + } + + public void setModelVersion(String modelVersion) { + this.modelVersion = modelVersion; + } + + /** + * Unmarshalls this Edge object into a JSON string. + * + * @return - A JSON format string representation of this Edge. + */ + public String toJson() { + return gson.toJson(this); + } + + /** + * Marshalls the provided JSON string into a Edge object. + * + * @param json - The JSON string to produce the Edge from. + * @return - A Edge object. + * @throws SpikeException + */ + public static GraphEventEdge fromJson(String json) throws ChampServiceException { + + try { + + // Make sure that we were actually provided a non-empty string + // before we + // go any further. + if (json == null || json.isEmpty()) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + + // Marshall the string into an Edge object. + return gson.fromJson(json, GraphEventEdge.class); + + } catch (Exception ex) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + } + + public static GraphEventEdge fromChampRelationship(ChampRelationship edge, String modelVersion) { + + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + JsonObject props = gson.toJsonTree(edge.getProperties(), mapType).getAsJsonObject(); + + GraphEventEdge graphEventEdge = new GraphEventEdge(edge.getKey().orElse("").toString(), modelVersion, + edge.getType(), new GraphEventVertex(edge.getSource().getKey().orElse("").toString(), null, + edge.getSource().getType(), null), new GraphEventVertex(edge.getTarget().getKey().orElse("").toString(), + null, edge.getTarget().getType(), null), props); + + return graphEventEdge; + + } + + public ChampRelationship toChampRelationship() { + ChampObject sourceChampObject=null; + ChampObject targetChampObject=null; + if (this.getSource() != null) { + sourceChampObject = new ChampObject.Builder(this.getSource().getType()).key(this.getSource().getId()) + .build(); + } + if (this.getTarget() != null) { + targetChampObject = new ChampObject.Builder(this.getTarget().getType()).key(this.getTarget().getId()) + .build(); + } + + ChampRelationship.Builder builder = new ChampRelationship.Builder(sourceChampObject, targetChampObject, type); + if(this.getId()!=null && !this.getId().isEmpty()){ + builder.key(this.getId()); + } + + + if (this.getProperties() != null) { + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + Map<String, Object> propertiesMap = gson.fromJson(this.getProperties(), mapType); + for (String key : propertiesMap.keySet()) { + builder.property(key, propertiesMap.get(key)); + } + } + return builder.build(); + + } +} diff --git a/champ-service/src/main/java/org/onap/champ/event/GraphEventVertex.java b/champ-service/src/main/java/org/onap/champ/event/GraphEventVertex.java new file mode 100644 index 0000000..553ba46 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/event/GraphEventVertex.java @@ -0,0 +1,187 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.event; + +import java.util.Map; + +import javax.ws.rs.core.Response.Status; + +import org.onap.aai.champcore.model.ChampObject; +import org.onap.champ.exception.ChampServiceException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +/** + * This class provides a generic representation of a Vertex as provided by the + * graph data store. + */ +public class GraphEventVertex { + + /** + * The unique identifier used to identify this vertex in the graph data + * store. + */ + @SerializedName("key") + private String id; + + @SerializedName("schema-version") + private String modelVersion; + + /** + * Type label assigned to this vertex. + */ + private String type; + + /** + * Map of all of the properties assigned to this vertex. + */ + private JsonElement properties; + + /** + * Marshaller/unmarshaller for converting to/from JSON. + */ + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + + public GraphEventVertex(String id, String modelVersion, String type, JsonElement properties) { + this.id = id; + this.modelVersion = modelVersion; + this.type = type; + this.properties = properties; + } + + public GraphEventVertex() { + + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + + public JsonElement getProperties() { + return properties; + } + + public void setProperties(JsonElement properties) { + this.properties = properties; + } + + public String getModelVersion() { + return modelVersion; + } + + public void setModelVersion(String modelVersion) { + this.modelVersion = modelVersion; + } + + /** + * Unmarshalls this Vertex object into a JSON string. + * + * @return - A JSON format string representation of this Vertex. + */ + public String toJson() { + return gson.toJson(this); + } + + /** + * Marshalls the provided JSON string into a Vertex object. + * + * @param json - The JSON string to produce the Vertex from. + * @return - A Vertex object. + * @throws SpikeException + */ + public static GraphEventVertex fromJson(String json) throws ChampServiceException { + + try { + + // Make sure that we were actually provided a non-empty string + // before we + // go any further. + if (json == null || json.isEmpty()) { + throw new ChampServiceException("Empty or null JSON string.", Status.BAD_REQUEST); + } + + // Marshall the string into a Vertex object. + return gson.fromJson(json, GraphEventVertex.class); + + } catch (Exception ex) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + } + + @Override + public String toString() { + + return toJson(); + } + + + public static GraphEventVertex fromChampObject(ChampObject champObject, String modelVersion) { + + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + JsonObject props = gson.toJsonTree(champObject.getProperties(), mapType).getAsJsonObject(); + GraphEventVertex graphEventVertex = new GraphEventVertex(champObject.getKey().orElse("").toString(), + modelVersion, champObject.getType(), props); + return graphEventVertex; + + } + + + public ChampObject toChampObject() { + ChampObject.Builder builder = new ChampObject.Builder(this.getType()); + if(this.getId()!=null && !this.getId().isEmpty()){ + builder.key(this.getId()); + } + + if (this.getProperties() != null) { + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + Map<String, Object> propertiesMap = gson.fromJson(this.getProperties(), mapType); + for (String key : propertiesMap.keySet()) { + builder.property(key, propertiesMap.get(key)); + } + } + + return builder.build(); + + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/exception/ChampServiceException.java b/champ-service/src/main/java/org/onap/champ/exception/ChampServiceException.java new file mode 100644 index 0000000..6e5e8c2 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/exception/ChampServiceException.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.champ.exception; + +import javax.ws.rs.core.Response.Status; + +public class ChampServiceException extends Exception { + + private static final long serialVersionUID = 8162385108397238865L; + + private Status httpStatus; + + public ChampServiceException() { + } + + public ChampServiceException(String message, Status httpStatus) { + super(message); + this.setHttpStatus(httpStatus); + } + + public ChampServiceException(Throwable cause) { + super(cause); + } + + public ChampServiceException(String message, Throwable cause) { + super(message, cause); + } + + public ChampServiceException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public Status getHttpStatus() { + return httpStatus; + } + + public void setHttpStatus(Status httpStatus) { + this.httpStatus = httpStatus; + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampDataService.java b/champ-service/src/main/java/org/onap/champ/service/ChampDataService.java new file mode 100644 index 0000000..7826fa2 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampDataService.java @@ -0,0 +1,355 @@ +package org.onap.champ.service; + +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.ChampElement; +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.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.service.logging.ChampMsgs; +import org.onap.champ.util.ChampProperties; +import org.onap.champ.util.ChampServiceConstants; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.ws.rs.core.Response.Status; + +public class ChampDataService { + private ChampUUIDService champUUIDService; + + private ChampGraph graphImpl; + private ChampTransactionCache cache; + private static final String KEY_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_KEY_NAME); + private static final String SOT_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_SOT_NAME); + private static final String CREATED_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_CREATED_TS_NAME); + private static final String LAST_MOD_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_LAST_MOD_TS_NAME); + private Logger logger = LoggerFactory.getInstance().getLogger(ChampDataService.class); + + + public ChampDataService(ChampUUIDService champUUIDService, ChampGraph graphImpl, ChampTransactionCache cache) { + + this.champUUIDService = champUUIDService; + this.graphImpl = graphImpl; + this.cache = cache; + } + + public ChampObject getObject(String id, Optional<ChampTransaction> transaction) throws ChampServiceException { + + Optional<ChampObject> retrieved = Optional.empty(); + try { + retrieved = champUUIDService.getObjectbyUUID(id, transaction.orElse(null)); + } catch (ChampUnmarshallingException | ChampTransactionException e) { + throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR); + } + if (retrieved.isPresent()) { + return (ChampObject) champUUIDService.populateUUIDKey(retrieved.get()); + } else { + return null; + } + } + + public ChampObject storeObject(ChampObject object, Optional<ChampTransaction> transaction) + throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, + ChampTransactionException, ChampServiceException { + + if (object.getProperty(KEY_NAME).isPresent() || object.getKey().isPresent()) { + throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST); + } + + champUUIDService.populateUUIDProperty(object, java.util.UUID.randomUUID().toString()); + addTimestamps(object, null); + ChampObject created = graphImpl.storeObject(object, transaction); + return (ChampObject) champUUIDService.populateUUIDKey(created); + } + + public ChampObject replaceObject(ChampObject object, String objectId, Optional<ChampTransaction> transaction) + throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException, + ChampSchemaViolationException, ChampObjectNotExistsException { + if (object.getKey().isPresent() && (!object.getKeyValue().equals(objectId))) { + throw new ChampServiceException("Object Id in the URI doesn't match the body.", Status.BAD_REQUEST); + } + + if (object.getProperty(KEY_NAME).isPresent() && !object.getProperty(KEY_NAME).get().toString().equals(objectId)) { + throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST); + } + + Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND); + } + ObjectBuildOrPropertiesStep payloadBuilder = ChampObject.create().from(object).withKey(retrieved.get().getKey().get()) + .withProperty(KEY_NAME, objectId); + if (retrieved.get().getProperty(SOT_NAME).isPresent()){ + payloadBuilder = payloadBuilder.withProperty(SOT_NAME, retrieved.get().getProperty(SOT_NAME).get()); + } + + if (object.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) { + // the timestamps in object are parsed as strings regardless of how the input json is. Convert retrieved to string for easy comparison + if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(object.getProperty(CREATED_TS_NAME).get())) { + throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + if (object.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) { + if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(object.getProperty(LAST_MOD_TS_NAME).get())) { + throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + ChampObject payload = payloadBuilder.build(); + addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null)); + ChampObject updated = graphImpl.replaceObject(payload, transaction); + return (ChampObject) champUUIDService.populateUUIDKey(updated); + } + + public void deleteObject(String objectId, Optional<ChampTransaction> transaction) throws ChampServiceException, + ChampObjectNotExistsException, ChampTransactionException, ChampUnmarshallingException { + Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND); + } + Stream<ChampRelationship> relationships = graphImpl.retrieveRelationships(retrieved.get(), transaction); + + if (relationships.count() > 0) { + throw new ChampServiceException("Attempt to delete vertex with id " + objectId + " which has incident edges.", + Status.BAD_REQUEST); + } + graphImpl.deleteObject(retrieved.get().getKey().get(), transaction); + + } + + public ChampRelationship storeRelationship(ChampRelationship r, Optional<ChampTransaction> transaction) + throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, + ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException, + ChampServiceException { + + if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null + || !r.getTarget().getKey().isPresent()) { + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target Object key must be provided"); + throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST); + } + + if (r.getProperty(KEY_NAME).isPresent() || r.getKey().isPresent()) { + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "key or " + KEY_NAME + " not allowed while creating new Objects"); + throw new ChampServiceException("key or " + KEY_NAME + " not allowed while creating new Objects", Status.BAD_REQUEST); + + } + + Optional<ChampObject> source = champUUIDService.getObjectbyUUID(r.getSource().getKey().get().toString(), + transaction.orElse(null)); + Optional<ChampObject> target = champUUIDService.getObjectbyUUID(r.getTarget().getKey().get().toString(), + transaction.orElse(null)); + + if (!source.isPresent() || !target.isPresent()) { + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target object not found"); + throw new ChampServiceException("Source/Target object not found", Status.BAD_REQUEST); + } + + champUUIDService.populateUUIDProperty(r, java.util.UUID.randomUUID().toString()); + + ChampRelationship payload = new ChampRelationship.Builder(source.get(), target.get(), r.getType()) + .properties(r.getProperties()).build(); + addTimestamps(payload, null); + ChampRelationship created = graphImpl.storeRelationship(payload, transaction); + return (ChampRelationship) champUUIDService.populateUUIDKey(created); + } + + public ChampRelationship updateRelationship(ChampRelationship r, String rId, Optional<ChampTransaction> transaction) + throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException, + ChampSchemaViolationException, ChampRelationshipNotExistsException { + if (r.getKey().isPresent() && (!r.getKeyValue().equals(rId))) { + + throw new ChampServiceException("Relationship Id in the URI \"" + rId + "\" doesn't match the URI in the body" + + " \"" + r.getKeyValue() + "\"", Status.BAD_REQUEST); + + } + + if (r.getProperty(KEY_NAME).isPresent() && !r.getProperty(KEY_NAME).get().toString().equals(rId)) { + throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST); + } + + Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(rId, transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(rId + " not found", Status.NOT_FOUND); + } + // check if key is present or if it equals the key that is in the URI + if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null + || !r.getTarget().getKey().isPresent()) { + throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST); + } + ChampObject source = retrieved.get().getSource(); + ChampObject target = retrieved.get().getTarget(); + + if (!source.getProperty(KEY_NAME).get().toString().equals(r.getSource().getKey().get().toString()) + || !target.getProperty(KEY_NAME).get().toString().equals(r.getTarget().getKey().get().toString())) { + throw new ChampServiceException("Source/Target cannot be updated", Status.BAD_REQUEST); + } + + if (r.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) { + if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(r.getProperty(CREATED_TS_NAME).get())) { + throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + if (r.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) { + if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(r.getProperty(LAST_MOD_TS_NAME).get())) { + throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + ChampRelationship payload = new ChampRelationship.Builder(source, target, r.getType()) + .key(retrieved.get().getKey().get()).properties(r.getProperties()).property(KEY_NAME, rId).build(); + addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null)); + ChampRelationship updated = graphImpl.replaceRelationship(payload, transaction); + return (ChampRelationship) champUUIDService.populateUUIDKey(updated); + } + + public void deleteRelationship(String relationshipId, Optional<ChampTransaction> transaction) + throws ChampServiceException, ChampRelationshipNotExistsException, ChampTransactionException, + ChampUnmarshallingException { + Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(relationshipId, + transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(relationshipId + " not found", Status.NOT_FOUND); + } + + graphImpl.deleteRelationship(retrieved.get(), transaction); + + } + + + public List<ChampRelationship> getRelationshipsByObject(String objectId, Optional<ChampTransaction> transaction) + throws ChampServiceException { + try { + Optional<ChampObject> retrievedObject = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null)); + if (!retrievedObject.isPresent()) { + throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND); + } + List<ChampRelationship> relations = new ArrayList<ChampRelationship>(); + + Stream<ChampRelationship> retrieved = graphImpl.retrieveRelationships(retrievedObject.get(), transaction); + relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList())); + return relations; + } catch (ChampObjectNotExistsException e) { + throw new ChampServiceException(" obj not found", Status.NOT_FOUND); + } catch (ChampUnmarshallingException | ChampTransactionException e) { + throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR); + } + + } + + /** + * Gets the ChampObjects that pass filter + * @param filter key/value pairs that must be present in the returned objects + * @param properties properties that will show up in the object + * @return + * @throws ChampServiceException + */ + public List<ChampObject> queryObjects(Map<String, Object> filter, HashSet<String> properties) throws ChampServiceException { + try { + + Stream<ChampObject> retrieved = graphImpl.queryObjects(filter); + List<ChampObject> objects = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList())); + + if (!properties.contains("all")) { + for (ChampObject champObject : objects) { + champObject.dropProperties(properties); + } + } + + return objects; + } catch (ChampTransactionException e) { + throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR); + } + } + + public List<ChampRelationship> queryRelationships(Map<String, Object> filter) throws ChampServiceException { + try { + List<ChampRelationship> relations = new ArrayList<ChampRelationship>(); + Stream<ChampRelationship> retrieved; + + retrieved = graphImpl.queryRelationships(filter); + + relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList())); + return relations; + } catch (ChampTransactionException e) { + throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR); + } + } + + public ChampRelationship getRelationship(String id, Optional<ChampTransaction> transaction) + throws ChampServiceException { + + Optional<ChampRelationship> retrieved = Optional.empty(); + try { + retrieved = champUUIDService.getRelationshipbyUUID(id, transaction.orElse(null)); + } catch (ChampUnmarshallingException | ChampTransactionException e) { + throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR); + } + if (retrieved.isPresent()) { + return (ChampRelationship) champUUIDService.populateUUIDKey(retrieved.get()); + } else { + return null; + } + } + + public String openTransaction() { + ChampTransaction transaction = graphImpl.openTransaction(); + String transacId = transaction.id(); + cache.put(transacId, transaction); + return transacId; + + } + + public void commitTransaction(String tId) throws ChampServiceException, ChampTransactionException { + ChampTransaction transaction = cache.get(tId); + if (transaction == null) { + throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND); + } + graphImpl.commitTransaction(transaction); + cache.invalidate(tId); + cache.invalidate(transaction.id()); + + } + + public void rollbackTransaction(String tId) throws ChampServiceException, ChampTransactionException { + ChampTransaction transaction = cache.get(tId); + if (transaction == null) { + throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND); + } + graphImpl.rollbackTransaction(transaction); + cache.invalidate(tId); + cache.invalidate(transaction.id()); + + } + + public ChampTransaction getTransaction(String id) { + return cache.get(id); + } + + private void addTimestamps(ChampElement e, Long oldCreated) { + Long timestamp = System.currentTimeMillis(); + + if (oldCreated == null) { + e.getProperties().put(CREATED_TS_NAME, timestamp); + } else { + e.getProperties().put(CREATED_TS_NAME, oldCreated); + } + + e.getProperties().put(LAST_MOD_TS_NAME, timestamp); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampThreadFactory.java b/champ-service/src/main/java/org/onap/champ/service/ChampThreadFactory.java new file mode 100644 index 0000000..25fe65e --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampThreadFactory.java @@ -0,0 +1,47 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.service; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Thread factory for workers. + */ +public class ChampThreadFactory implements ThreadFactory { + + private AtomicInteger threadNumber = new AtomicInteger(1); + + private String threadPrefix; + + + public ChampThreadFactory(String threadPrefix) { + this.threadPrefix = threadPrefix; + } + + public Thread newThread(Runnable runnable) { + return new Thread(runnable, threadPrefix + "-" + threadNumber.getAndIncrement()); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampTransactionCache.java b/champ-service/src/main/java/org/onap/champ/service/ChampTransactionCache.java new file mode 100644 index 0000000..bb95147 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampTransactionCache.java @@ -0,0 +1,77 @@ + +package org.onap.champ.service; + +import java.util.concurrent.TimeUnit; + +import org.onap.aai.champcore.ChampGraph; +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.champcore.exceptions.ChampTransactionException; +import org.onap.champ.service.logging.ChampMsgs; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalCause; +import com.google.common.cache.RemovalListener; +import com.google.common.cache.RemovalNotification; + +/** + * Self expiring Cache to hold request transactionIds . Events are expired + * automatically after configured interval + */ +public class ChampTransactionCache { + private static Logger logger = LoggerFactory.getInstance().getLogger(ChampTransactionCache + .class.getName()); + + + private ChampGraph graphImpl; + private Cache<String, ChampTransaction> cache; + + + + public ChampTransactionCache(long txTimeOutInSec,ChampGraph graphImpl) { + CacheBuilder builder = CacheBuilder.newBuilder().expireAfterWrite(txTimeOutInSec, TimeUnit.SECONDS) + .removalListener(new RemovalListener() { + + public void onRemoval(RemovalNotification notification) { + if(notification.getCause()==RemovalCause.EXPIRED){ + logger.info(ChampMsgs.CHAMP_TX_CACHE, "Following transaction: "+notification.getKey()+" is being evicted from cache due to timeout of " + txTimeOutInSec+" seconds"); + try { + graphImpl.rollbackTransaction((ChampTransaction) notification.getValue()); + logger.info(ChampMsgs.CHAMP_TX_CACHE, "Transaction rolledback successfully :" + notification.getKey()); + } catch (ChampTransactionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + }); + cache = builder.build(); + + this.graphImpl = graphImpl; + + } + + public void put(String txId, ChampTransaction tx) { + cache.put(txId, tx); + + } + + public ChampTransaction get(String txId) { + if (txId==null) + return null; + if(cache.getIfPresent(txId)==null){ + //cleanup cache so that removalListener is called + cache.cleanUp(); + } + return cache.getIfPresent(txId); + } + + public void invalidate(String txId) { + cache.invalidate(txId); + } + + + +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampUUIDService.java b/champ-service/src/main/java/org/onap/champ/service/ChampUUIDService.java new file mode 100644 index 0000000..39c775b --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampUUIDService.java @@ -0,0 +1,115 @@ +package org.onap.champ.service; + +import org.onap.aai.champcore.ChampGraph; +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.champcore.exceptions.ChampTransactionException; +import org.onap.aai.champcore.exceptions.ChampUnmarshallingException; +import org.onap.aai.champcore.model.ChampElement; +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.util.ChampProperties; +import org.onap.champ.util.ChampServiceConstants; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +public class ChampUUIDService { + private ChampGraph graphImpl; + private static final String KEY_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_KEY_NAME); + + + public ChampUUIDService(ChampGraph graphImpl) { + this.graphImpl = graphImpl; + } + + public List populateUUIDKey(List<ChampElement> elements) { + { + List response = new ArrayList(); + for (ChampElement e : elements) { + ChampElement item = populateUUIDKey(e); + if (item != null) { + response.add(item); + } + } + return response; + } + + } + + public ChampElement populateUUIDKey(ChampElement e) { + { + ChampElement response = null; + + if (e.isObject()) { + if (e.asObject().getProperty(KEY_NAME).isPresent()) { + response = (ChampObject.create().from(e.asObject()) + .withKey(e.asObject().getProperty(KEY_NAME).get().toString()).build()); + } + } else { + if (e.asRelationship().getProperty(KEY_NAME).isPresent() + && e.asRelationship().getSource().getProperty(KEY_NAME).isPresent() + && e.asRelationship().getTarget().getProperty(KEY_NAME).isPresent()) { + ChampObject source = ChampObject.create().from(e.asRelationship().getSource()) + .withKey(e.asRelationship().getSource().getProperty(KEY_NAME).get().toString()).build(); + ChampObject target = ChampObject.create().from(e.asRelationship().getTarget()) + .withKey(e.asRelationship().getTarget().getProperty(KEY_NAME).get().toString()).build(); + ChampRelationship rel = new ChampRelationship.Builder(source, target, e.asRelationship().getType()) + .key(e.asRelationship().getProperty(KEY_NAME).get().toString()) + .properties(e.asRelationship().getProperties()).build(); + response = rel; + } + + } + + return response; + } + + } + + public void populateUUIDProperty(ChampElement e, String uuid) { + e.getProperties().put(KEY_NAME, uuid); + } + + + public Optional<ChampObject> getObjectbyUUID(String uuid, ChampTransaction transaction) + throws ChampUnmarshallingException, ChampTransactionException, ChampServiceException { + Optional<ChampObject> response = Optional.empty(); + + Stream<ChampObject> s; + Map<String, Object> filter = new HashMap<>(); + filter.put(KEY_NAME, uuid); + + s = graphImpl.queryObjects(filter, Optional.ofNullable(transaction)); + Object[] objs = s.toArray(); + if (objs.length == 0) { + return response; + } + response = graphImpl.retrieveObject(((ChampObject) objs[0]).getKey().get(), Optional.ofNullable(transaction)); + return response; + } + + public Optional<ChampRelationship> getRelationshipbyUUID(String uuid, ChampTransaction transaction) + throws ChampUnmarshallingException, ChampTransactionException, ChampServiceException { + Optional<ChampRelationship> response = Optional.empty(); + + + Stream<ChampRelationship> s; + Map<String, Object> filter = new HashMap<>(); + filter.put(KEY_NAME, uuid); + + s = graphImpl.queryRelationships(filter, Optional.ofNullable(transaction)); + Object[] objs = s.toArray(); + if (objs.length == 0) { + return response; + } + response = graphImpl.retrieveRelationship(((ChampRelationship) objs[0]).getKey().get(), + Optional.ofNullable(transaction)); + return response; + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/service/EchoService.java b/champ-service/src/main/java/org/onap/champ/service/EchoService.java new file mode 100644 index 0000000..c8236b1 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/EchoService.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.champ.service; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + + +public class EchoService { + + private static Logger logger = LoggerFactory.getInstance() + .getLogger(EchoService.class.getName()); + private static Logger auditLogger = LoggerFactory.getInstance() + .getAuditLogger(EchoService.class.getName()); + + @GET + @Path("echo/{input}") + @Produces("text/plain") + public String ping(@PathParam("input") String input, + @Context HttpHeaders headers, + @Context UriInfo info, + @Context HttpServletRequest req) { + + return "Hello, " + input + "."; + } +}
\ No newline at end of file diff --git a/champ-service/src/main/java/org/onap/champ/service/logging/ChampMsgs.java b/champ-service/src/main/java/org/onap/champ/service/logging/ChampMsgs.java new file mode 100644 index 0000000..2ddbff4 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/logging/ChampMsgs.java @@ -0,0 +1,130 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.champ.service.logging; + +import com.att.eelf.i18n.EELFResourceManager; +import org.onap.aai.cl.eelf.LogMessageEnum; + +public enum ChampMsgs implements LogMessageEnum { + + /** + * Received request {0} {1} from {2}. Sending response: {3} + * + * <p> + * Arguments: {0} = operation {1} = target URL {2} = source {3} = response + * code + */ + PROCESS_REST_REQUEST, + /** + * Processed event {0}. Result: {1}. + * + * Arguments: {0} = event {1} = result + */ + PROCESS_EVENT, + + /** + * Query: {0} + * Arguments: {0} = query + */ + QUERY, + + /** + * Arguments: {0} = transactionID, {1} = request + */ + INCOMING_REQUEST, + + /** + * Arguments: {0} = HTTP request type, {1} = time to process in milliseconds + */ + PROCESSED_REQUEST, + + /** + * Arguments: {0} = transaction ID + */ + TRANSACTION_NOT_FOUND, + + /** + * Arguments: {0} = request, {1} = Error + */ + BAD_REQUEST, + + /** + * Arguments: {0} = Info + */ + CHAMP_TX_CACHE, + + /** + * Any info log related to CHAMP_ASYNC_REQUEST_PROCESSOR_INFO + * + * <p>Arguments: + * {0} - Info. + */ + CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + CHAMP_ASYNC_REQUEST_PROCESSOR_WARN, + + /** + * Any error log related to CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR + * + * <p>Arguments: + * {0} - Error. + */ + CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + + /** + * Any info log related to CHAMP_DATA_SERVICE_INFO + * + * <p>Arguments: + * {0} - Info. + */ + CHAMP_DATA_SERVICE_INFO, + + /** + * Any error log related to CHAMP_DATA_SERVICE_INFO + * + * <p>Arguments: + * {0} - Error. + */ + CHAMP_DATA_SERVICE_ERROR, + + + /** + * Any info log related to CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO + * + * <p>Arguments: + * {0} - Info. + */ + CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + + /** + * Any error log related to CHAMP_ASYNC_RESPONSE_PUBLISHER_ERROR + * + * <p>Arguments: + * {0} - Error. + */ + CHAMP_ASYNC_RESPONSE_PUBLISHER_ERROR; + /** + * Static initializer to ensure the resource bundles for this class are loaded... + */ + static { + EELFResourceManager.loadMessageBundle("logging/ChampMsgs"); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/logging/LoggingUtil.java b/champ-service/src/main/java/org/onap/champ/service/logging/LoggingUtil.java new file mode 100644 index 0000000..b7f0e77 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/logging/LoggingUtil.java @@ -0,0 +1,92 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.champ.service.logging; + +import org.onap.aai.cl.api.LogFields; +import org.onap.aai.cl.api.LogLine; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.mdc.MdcContext; + +import org.slf4j.MDC; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; + +public class LoggingUtil { + /** + * Initializes mdc context. + */ + public static void initMdcContext(HttpServletRequest httpReq, HttpHeaders headers) { + String fromIp = httpReq.getRemoteAddr(); + String fromAppId = ""; + String transId = null; + + if (headers.getRequestHeaders().getFirst("X-FromAppId") != null) { + fromAppId = headers.getRequestHeaders().getFirst("X-FromAppId"); + } + + if ((headers.getRequestHeaders().getFirst("X-TransactionId") == null) + || headers.getRequestHeaders().getFirst("X-TransactionId").isEmpty()) { + transId = java.util.UUID.randomUUID().toString(); + } else { + transId = headers.getRequestHeaders().getFirst("X-TransactionId"); + } + + MdcContext.initialize(transId, "ChampService", "", fromAppId, fromIp); + } + + /** + * Logs the rest request. + */ + public static void logRestRequest(Logger logger, Logger auditLogger, HttpServletRequest req, Response response) { + String respStatusString = ""; + if (Response.Status.fromStatusCode(response.getStatus()) != null) { + respStatusString = Response.Status.fromStatusCode(response.getStatus()).toString(); + } + + // Generate error log + logger.info(ChampMsgs.PROCESS_REST_REQUEST, req.getMethod(), req.getRequestURL().toString(), + req.getRemoteHost(), Integer.toString(response.getStatus())); + + // Generate audit log. + auditLogger.info(ChampMsgs.PROCESS_REST_REQUEST, + new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, response.getStatus()) + .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, respStatusString), + (req != null) ? req.getMethod() : "Unknown", (req != null) ? req.getRequestURL().toString() : "Unknown", + (req != null) ? req.getRemoteHost() : "Unknown", Integer.toString(response.getStatus()) + " payload: " + + (response.getEntity() == null ? "" : response.getEntity().toString())); + MDC.clear(); + } + + public static void logInternalError(Logger logger, Exception ex) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Internal error: " + ex.getMessage() + "\n" + writer.toString()); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/util/ChampProperties.java b/champ-service/src/main/java/org/onap/champ/util/ChampProperties.java new file mode 100644 index 0000000..178da97 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/util/ChampProperties.java @@ -0,0 +1,53 @@ +package org.onap.champ.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +public class ChampProperties { + + private static Properties properties; + + static { + properties = new Properties(); + File file = new File(ChampServiceConstants.CHAMP_CONFIG_FILE); + try { + properties.load(new FileInputStream(file)); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(1); + } + } + + public static String get(String key) { + return properties.getProperty(key); + } + + public static String get(String key, String defaultValue) { + return properties.getProperty(key, defaultValue); + } + + public static void put(String key, String value) { + properties.setProperty(key, value); + FileOutputStream fileOut = null; + try { + fileOut = new FileOutputStream(new File(ChampServiceConstants.CHAMP_CONFIG_FILE)); + properties.store(fileOut, "Added property: " + key); + } catch (Exception e) { + e.printStackTrace(); + } finally { + + try { + fileOut.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + } + + +} diff --git a/champ-service/src/main/java/org/onap/champ/util/ChampServiceConstants.java b/champ-service/src/main/java/org/onap/champ/util/ChampServiceConstants.java new file mode 100644 index 0000000..94a9972 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/util/ChampServiceConstants.java @@ -0,0 +1,14 @@ +package org.onap.champ.util; + +public class ChampServiceConstants { + public static final String CHAMP_FILESEP = (System.getProperty("file.separator") == null) ? "/" + : System.getProperty("file.separator"); + + public static final String CHAMP_SPECIFIC_CONFIG = System.getProperty("CONFIG_HOME") + CHAMP_FILESEP; + public static final String CHAMP_CONFIG_FILE = CHAMP_SPECIFIC_CONFIG + "champ-api.properties"; + public static final String CHAMP_KEY_NAME = "keyName"; + public static final String CHAMP_SOT_NAME = "sourceOfTruthName"; + public static final String CHAMP_CREATED_TS_NAME = "createdTsName"; + public static final String CHAMP_LAST_MOD_TS_NAME = "lastModTsName"; + public static final String CHAMP_COLLECTION_PROPERTIES_KEY = "collectionPropertiesKey"; +}
\ No newline at end of file diff --git a/champ-service/src/main/resources/META-INF/services/javax.ws.rs.client.ClientBuilder b/champ-service/src/main/resources/META-INF/services/javax.ws.rs.client.ClientBuilder new file mode 100644 index 0000000..48b9fa5 --- /dev/null +++ b/champ-service/src/main/resources/META-INF/services/javax.ws.rs.client.ClientBuilder @@ -0,0 +1 @@ +org.glassfish.jersey.client.JerseyClientBuilder
\ No newline at end of file diff --git a/champ-service/src/main/resources/logging/ChampMsgs.properties b/champ-service/src/main/resources/logging/ChampMsgs.properties new file mode 100644 index 0000000..776b178 --- /dev/null +++ b/champ-service/src/main/resources/logging/ChampMsgs.properties @@ -0,0 +1,78 @@ +#Resource key=Error Code|Message text|Resolution text |Description text +####### +#Newlines can be utilized to add some clarity ensuring continuing line +#has atleast one leading space +#ResourceKey=\ +# ERR0000E\ +# Sample error msg txt\ +# Sample resolution msg\ +# Sample description txt +# +###### +#Error code classification category +#000 Info/Debug +#100 Permission errors +#200 Availability errors/Timeouts +#300 Data errors +#400 Schema Interface type/validation errors +#500 Business process errors +#900 Unknown errors +# +######################################################################## +PROCESS_REST_REQUEST=\ + CS0005I|\ + Received request {0} {1} from {2}. Sending response: {3}|\ + None. Received the specified REST request from the source specified.|\ + Received the specified REST request from the source specified, and the CHAMP service sent the specified response. + +PROCESS_EVENT=\ + CS0001I|\ + Processed event {0} Result: {1} + +QUERY=\ + CS0002I|\ + Query Recieved: {0} + +INCOMING_REQUEST=\ + CS0003I|\ + Incoming Request with Transaction ID {0} and request {1} + +PROCESSED_REQUEST=\ + CS0004I|\ + Processed Champ {0} request in {1} ms + +TRANSACTION_NOT_FOUND=\ + CS0001E|\ + Transaction with ID {0} was not found. + +BAD_REQUEST=\ + CS0002E|\ + Bad Request {0}. Error is {1} + +CHAMP_TX_CACHE=\ + CS0006I|\ + ChampTransactionCache: {0} +CHAMP_DATA_SERVICE_ERROR=\ + CRD0510E|\ + ChampDataService Error: {0} +CHAMP_DATA_CACHE_INFO=\ + CRD0511I|\ + ChampDataService: {0} +CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR=\ + CRD0512E|\ + ChampAsyncRequestProcessor Error: {0} +CHAMP_ASYNC_REQUEST_PROCESSOR_WARN=\ + CRD0514E|\ + ChampAsyncRequestProcessor Warning: {0} +CHAMP_ASYNC_REQUEST_PROCESSOR_INFO=\ + CRD0512I|\ + ChampAsyncRequestProcessor: {0} +CHAMP_ASYNC_RESPONSE_PUBLISHER_ERROR=\ + CRD0513E|\ + ChampAsyncRequestProcessor Error: {0} +CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO=\ + CRD0513I|\ + ChampAsyncRequestProcessor: {0} + + + diff --git a/champ-service/src/main/runtime/context/__module.ajsc.namespace.name__#__module.ajsc.namespace.version__.context b/champ-service/src/main/runtime/context/__module.ajsc.namespace.name__#__module.ajsc.namespace.version__.context new file mode 100644 index 0000000..8514196 --- /dev/null +++ b/champ-service/src/main/runtime/context/__module.ajsc.namespace.name__#__module.ajsc.namespace.version__.context @@ -0,0 +1 @@ +{"context":{"contextClass":"ajsc.Context","contextId":"__module_ajsc_namespace_name__:__module_ajsc_namespace_version__","contextName":"__module_ajsc_namespace_name__","contextVersion":"__module_ajsc_namespace_version__","description":"__module_ajsc_namespace_name__ Context"}}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/context/default#0.context b/champ-service/src/main/runtime/context/default#0.context new file mode 100644 index 0000000..d1b5ab4 --- /dev/null +++ b/champ-service/src/main/runtime/context/default#0.context @@ -0,0 +1 @@ +{"context":{"contextClass":"ajsc.Context","contextId":"default:0","contextName":"default","contextVersion":"0","description":"Default Context"}}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/deploymentPackage/__module.ajsc.namespace.name__#__module.ajsc.namespace.version__.json b/champ-service/src/main/runtime/deploymentPackage/__module.ajsc.namespace.name__#__module.ajsc.namespace.version__.json new file mode 100644 index 0000000..d0954cf --- /dev/null +++ b/champ-service/src/main/runtime/deploymentPackage/__module.ajsc.namespace.name__#__module.ajsc.namespace.version__.json @@ -0,0 +1 @@ +{"deploymentPackage":{"Class":"ajsc.DeploymentPackage","Id":"__module.ajsc.namespace.name__:__module_ajsc_namespace_version__","namespace":"__module_ajsc_namespace_name__","namespaceVersion":"__module_ajsc_namespace_version__","description":"__module_ajsc_namespace_name__ __module_ajsc_namespace_version__ - default description","userId":"ajsc"}}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/shiroRole/ajscadmin.json b/champ-service/src/main/runtime/shiroRole/ajscadmin.json new file mode 100644 index 0000000..f5e981e --- /dev/null +++ b/champ-service/src/main/runtime/shiroRole/ajscadmin.json @@ -0,0 +1 @@ +{"shiroRoleClass":"ajsc.auth.ShiroRole","shiroRoleId":"ajscadmin","name":"ajscadmin","permissions":"[ajscadmin:*, ajsc:*]"}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/shiroRole/contextadmin#__module.ajsc.namespace.name__.json b/champ-service/src/main/runtime/shiroRole/contextadmin#__module.ajsc.namespace.name__.json new file mode 100644 index 0000000..2dae9f5 --- /dev/null +++ b/champ-service/src/main/runtime/shiroRole/contextadmin#__module.ajsc.namespace.name__.json @@ -0,0 +1 @@ +{"shiroRoleClass":"ajsc.auth.ShiroRole","shiroRoleId":"contextadmin:__module_ajsc_namespace_name__","name":"contextadmin:__module_ajsc_namespace_name__","permissions":"[]"}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/shiroRole/contextadmin#default.json b/champ-service/src/main/runtime/shiroRole/contextadmin#default.json new file mode 100644 index 0000000..5de814e --- /dev/null +++ b/champ-service/src/main/runtime/shiroRole/contextadmin#default.json @@ -0,0 +1 @@ +{"shiroRoleClass":"ajsc.auth.ShiroRole","shiroRoleId":"contextadmin:default","name":"contextadmin:default","permissions":"[]"}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/shiroUser/ajsc.json b/champ-service/src/main/runtime/shiroUser/ajsc.json new file mode 100644 index 0000000..f4c7855 --- /dev/null +++ b/champ-service/src/main/runtime/shiroUser/ajsc.json @@ -0,0 +1 @@ +{"shiroUserClass":"ajsc.auth.ShiroUser","shiroUserId":"ajsc","passwordHash":"9471697417008c880720ba54c6038791ad7e98f3b88136fe34f4d31a462dd27a","permissions":"[*:*]","username":"ajsc"}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/shiroUserRole/ajsc#ajscadmin.json b/champ-service/src/main/runtime/shiroUserRole/ajsc#ajscadmin.json new file mode 100644 index 0000000..cb8d483 --- /dev/null +++ b/champ-service/src/main/runtime/shiroUserRole/ajsc#ajscadmin.json @@ -0,0 +1 @@ +{"shiroUserRoleClass":"ajsc.auth.ShiroUserRole","shiroUserRoleId":"ajsc:ajscadmin","roleId":"ajscadmin","userId":"ajsc"}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/shiroUserRole/ajsc#contextadmin#__module.ajsc.namespace.name__.json b/champ-service/src/main/runtime/shiroUserRole/ajsc#contextadmin#__module.ajsc.namespace.name__.json new file mode 100644 index 0000000..95d2361 --- /dev/null +++ b/champ-service/src/main/runtime/shiroUserRole/ajsc#contextadmin#__module.ajsc.namespace.name__.json @@ -0,0 +1 @@ +{"shiroUserRoleClass":"ajsc.auth.ShiroUserRole","shiroUserRoleId":"ajsc:contextadmin:__module_ajsc_namespace_name__","roleId":"contextadmin:__module_ajsc_namespace_name__","userId":"ajsc"}
\ No newline at end of file diff --git a/champ-service/src/main/runtime/shiroUserRole/ajsc#contextadmin#default.json b/champ-service/src/main/runtime/shiroUserRole/ajsc#contextadmin#default.json new file mode 100644 index 0000000..2bd5063 --- /dev/null +++ b/champ-service/src/main/runtime/shiroUserRole/ajsc#contextadmin#default.json @@ -0,0 +1 @@ +{"shiroUserRoleClass":"ajsc.auth.ShiroUserRole","shiroUserRoleId":"ajsc:contextadmin:default","roleId":"contextadmin:default","userId":"ajsc"}
\ No newline at end of file @@ -1,398 +1,18 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.onap.oparent</groupId> - <artifactId>oparent</artifactId> - <version>1.0.0-SNAPSHOT</version> - </parent> +<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> - <groupId>org.onap.aai</groupId> - <artifactId>champ</artifactId> - <version>1.1.0-SNAPSHOT</version> - <name>aai-champ</name> - <properties> - <tinkerpop.version>3.0.1-incubating</tinkerpop.version> - <sitePath>/content/sites/site/org/onap/aai/${project.artifactId}/${project.version}</sitePath> - <sonar.language>java</sonar.language> - <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin> - <sonar.surefire.reportsPath>${project.build.directory}/surefire-reports</sonar.surefire.reportsPath> - <sonar.jacoco.reportPath>${project.build.directory}/code-coverage/jacoco-ut.exec</sonar.jacoco.reportPath> - <sonar.jacoco.reportMissing.force.zero>false</sonar.jacoco.reportMissing.force.zero> - <sonar.projectVersion>${project.version}</sonar.projectVersion> - </properties> - <distributionManagement> - <site> - <id>ecomp-site</id> - <url>dav:${onap.nexus.url}${sitePath}</url> - </site> - </distributionManagement> - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-classic</artifactId> - <version>1.2.1</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>org.apache.tinkerpop</groupId> - <artifactId>tinkergraph-gremlin</artifactId> - <version>${tinkerpop.version}</version> - </dependency> - <dependency> - <groupId>org.apache.tinkerpop</groupId> - <artifactId>gremlin-core</artifactId> - <version>${tinkerpop.version}</version> - <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>com.thinkaurelius.titan</groupId> - <artifactId>titan-cassandra</artifactId> - <version>1.0.0</version> - <optional>true</optional> - <exclusions> - <exclusion> - <groupId>org.apache.tinkerpop</groupId> - <artifactId>gremlin-groovy</artifactId> - </exclusion> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - </exclusion> - <exclusion> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-classic</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.tinkerpop</groupId> - <artifactId>gremlin-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>com.thinkaurelius.titan</groupId> - <artifactId>titan-hbase</artifactId> - <version>1.0.0</version> - <optional>true</optional> - <exclusions> - <exclusion> - <groupId>org.apache.tinkerpop</groupId> - <artifactId>gremlin-groovy</artifactId> - </exclusion> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - </exclusion> - <exclusion> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-classic</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.tinkerpop</groupId> - <artifactId>gremlin-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.hbase</groupId> - <artifactId>hbase-client</artifactId> - <version>0.98.4-hadoop2</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - </exclusion> - <exclusion> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>jdk.tools</groupId> - <artifactId>jdk.tools</artifactId> - <version>1.8</version> - <scope>system</scope> - <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath> - </dependency> - <dependency> - <groupId>org.jacoco</groupId> - <artifactId>org.jacoco.agent</artifactId> - <version>0.7.9</version> - <classifier>runtime</classifier> - <scope>test</scope> - </dependency> + <groupId>org.onap.aai</groupId> + <artifactId>champ</artifactId> + <name>cc-champ</name> + <packaging>pom</packaging> + <version>1.2.0-SNAPSHOT</version> - <!-- Event Bus Client. --> - <dependency> - <groupId>com.att.nsa</groupId> - <artifactId>cambriaClient</artifactId> - <version>0.0.1</version> - </dependency> - - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - <version>4.5</version> - </dependency> - - </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>sonar-maven-plugin</artifactId> - <version>3.2</version> - </plugin> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> - <configuration> - <excludes> - <!-- These three need to be included again at some point --> - <exclude>**/AbstractGremlinChampGraph*</exclude> - <exclude>**/DseChampGraphImpl*</exclude> - <exclude>**/DseChampformer*</exclude> - <!-- Permanently excluded, not worth testing --> - <exclude>**/ChampAPIPerformanceTest*</exclude> - </excludes> - </configuration> - <executions> - <execution> - <id>default-prepare-agent</id> - <goals> - <goal>prepare-agent</goal> - </goals> - </execution> - <execution> - <id>default-report</id> - <phase>prepare-package</phase> - <goals> - <goal>report</goal> - </goals> - </execution> - <execution> - <id>default-check</id> - <goals> - <goal>check</goal> - </goals> - <configuration> - <rules> - <!-- implementation is needed only for Maven 2 --> - <rule implementation="org.jacoco.maven.RuleConfiguration"> - <element>BUNDLE</element> - <limits> - <!-- implementation is needed only for Maven 2 --> - <limit implementation="org.jacoco.report.check.Limit"> - <counter>INSTRUCTION</counter> - <value>COVEREDRATIO</value> - <minimum>.75</minimum> - </limit> - <limit implementation="org.jacoco.report.check.Limit"> - <counter>BRANCH</counter> - <value>COVEREDRATIO</value> - <minimum>.74</minimum> - </limit> - <limit implementation="org.jacoco.report.check.Limit"> - <counter>COMPLEXITY</counter> - <value>COVEREDRATIO</value> - <minimum>.75</minimum> - </limit> - <limit implementation="org.jacoco.report.check.Limit"> - <counter>LINE</counter> - <value>COVEREDRATIO</value> - <minimum>.80</minimum> - </limit> - <limit implementation="org.jacoco.report.check.Limit"> - <counter>METHOD</counter> - <value>COVEREDRATIO</value> - <minimum>.90</minimum> - </limit> - <limit implementation="org.jacoco.report.check.Limit"> - <counter>CLASS</counter> - <value>MISSEDCOUNT</value> - <maximum>0</maximum> - </limit> - </limits> - </rule> - </rules> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <version>3.0.0</version> - <configuration> - <descriptorRefs> - <descriptorRef>jar-with-dependencies</descriptorRef> - </descriptorRefs> - </configuration> - <executions> - <execution> - <id>make-jar-with-dependencies</id> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.6.1</version> - <configuration> - <source>1.8</source> - <target>1.8</target> - </configuration> - </plugin> - <plugin> - <artifactId>maven-release-plugin</artifactId> - <version>2.4.2</version> - <dependencies> - <dependency> - <groupId>org.apache.maven.scm</groupId> - <artifactId>maven-scm-provider-gitexe</artifactId> - <version>1.8.1</version> - </dependency> - </dependencies> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - <version>3.0.1</version> - <executions> - <execution> - <id>attach-sources</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - <version>2.9.1</version> - <executions> - <execution> - <id>attach-javadocs</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile> - </systemPropertyVariables> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-deploy-plugin</artifactId> - <version>2.8.2</version> - <executions> - <execution> - <id>default-deploy</id> - <phase>none</phase> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.sonatype.plugins</groupId> - <artifactId>nexus-staging-maven-plugin</artifactId> - <version>1.6.7</version> - <extensions>true</extensions> - <configuration> - <nexusUrl>${onap.nexus.url}</nexusUrl> - <stagingProfileId>176c31dfe190a</stagingProfileId> - <serverId>ecomp-staging</serverId> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-site-plugin</artifactId> - <version>3.6</version> - <dependencies> - <dependency> - <groupId>org.apache.maven.wagon</groupId> - <artifactId>wagon-webdav-jackrabbit</artifactId> - <version>2.10</version> - </dependency> - </dependencies> - </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> - <reporting> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - <version>2.10.4</version> - <configuration> - <failOnError>false</failOnError> - <doclet>org.umlgraph.doclet.UmlGraphDoc</doclet> - <docletArtifact> - <groupId>org.umlgraph</groupId> - <artifactId>umlgraph</artifactId> - <version>5.6</version> - </docletArtifact> - <additionalparam>-views</additionalparam> - <useStandardDocletOptions>true</useStandardDocletOptions> - </configuration> - </plugin> - </plugins> - </reporting> -</project> + <modules> + <module>champ-lib</module> + <module>champ-service</module> + <module>champ-service-deps-janus</module> + <module>champ-service-deps-titan</module> + </modules> + +</project>
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/champ/ChampGraph.java b/src/main/java/org/onap/aai/champ/ChampGraph.java deleted file mode 100644 index 2762e43..0000000 --- a/src/main/java/org/onap/aai/champ/ChampGraph.java +++ /dev/null @@ -1,308 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ; - -import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; - -import org.onap.aai.champ.exceptions.ChampIndexNotExistsException; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.graph.impl.InMemoryChampGraphImpl; -import org.onap.aai.champ.graph.impl.TitanChampGraphImpl; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampRelationshipIndex; -import org.onap.aai.champ.model.ChampSchema; - -public interface ChampGraph { - - /** - * Types that the Factory is capable of constructing - */ - public enum Type { - IN_MEMORY, - TITAN/*, - DSE //DSE is still in beta, so leave it out for now - */ - } - - /** - * 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(){ - //not called - } - public static ChampGraph newInstance(ChampGraph.Type type, String graphName) { - switch (type) { - case IN_MEMORY: - return new InMemoryChampGraphImpl.Builder().build(); - case TITAN: - return new TitanChampGraphImpl.Builder(graphName) - .property("storage.backend", "inmemory") - .build(); - /* - case DSE: //See above, DSE still in beta - */ - default: - throw new RuntimeException("Unknown type of ChampAPI implementation"); - } - } - } - - /** - * Create/Update an object. 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.champ.model.ChampObject#getKey}.isPresent() but the object cannot be found in the graph - */ - public ChampObject storeObject(ChampObject object) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException; - - /** - * Replace an object. ChampObject key is mandatory - * 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.champ.model.ChampObject#getKey} is not present or object not found in the graph - */ - public ChampObject replaceObject(ChampObject object) throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException; - - /** - * Retrieve an object by its key. - * @param key The key of the ChampObject in the graph {@link org.onap.aai.champ.model.ChampObject#getKey()} - * @return The {@link org.onap.aai.champ.model.ChampObject} if it was present, otherwise {@link Optional#empty()} - * @throws ChampUnmarshallingException If the object was found, but could not be unmarshalled - */ - public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException; - - /** - * 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 - */ - public void deleteObject(Object key) throws ChampObjectNotExistsException; - - /** - * 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} - */ - public Stream<ChampObject> queryObjects(Map<String, Object> queryParams); - - /** - * Create/Update a relationship. 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.champ.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 - */ - public ChampRelationship storeRelationship(ChampRelationship relationship) throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampUnmarshallingException; - - /** - * Replace a relationship. 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 - * 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.champ.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 - */ - public ChampRelationship replaceRelationship(ChampRelationship relationship) throws ChampMarshallingException, ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampUnmarshallingException; - - - /** - * Retrieve a relationship by its key. - * @param key The key of the ChampRelationship in the graph {@link org.onap.aai.champ.model.ChampRelationship#getKey()} - * @return The {@link org.onap.aai.champ.model.ChampRelationship} if it was present, otherwise {@link Optional#empty()} - * @throws ChampUnmarshallingException If the relationship was found, but could not be unmarshalled - */ - public Optional<ChampRelationship> retrieveRelationship(Object key) throws ChampUnmarshallingException; - - /** - * 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 - */ - public void deleteRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException; - - /** - * 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 - */ - public Stream<ChampRelationship> retrieveRelationships(ChampObject object) throws ChampUnmarshallingException, ChampObjectNotExistsException; - - /** - * 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} - */ - public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams); - - /** - * 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. 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 - * @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; - - /** - * Delete the {@code partition} from the graph - * @param partition The partition to delete from the graph - */ - public void deletePartition(ChampPartition partition); - - /** - * 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/src/main/java/org/onap/aai/champ/graph/impl/AbstractGremlinChampGraph.java b/src/main/java/org/onap/aai/champ/graph/impl/AbstractGremlinChampGraph.java deleted file mode 100644 index 8f806bf..0000000 --- a/src/main/java/org/onap/aai/champ/graph/impl/AbstractGremlinChampGraph.java +++ /dev/null @@ -1,350 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.graph.impl; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.structure.VertexProperty; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.graph.impl.TitanChampGraphImpl.Builder; -import org.onap.aai.champ.model.ChampElement; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.fluent.partition.CreateChampPartitionable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractGremlinChampGraph extends AbstractValidatingChampGraph { - - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGremlinChampGraph.class); - - protected abstract GraphTraversalSource startTraversal(); - protected abstract Stream<ChampElement> runTraversal(GraphTraversal<?, ?> traversal); - - protected AbstractGremlinChampGraph(Map<String, Object> properties) { - super(properties); - } - - @Override - public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Stream<ChampElement> elements = runTraversal(startTraversal().V(key).limit(1)); - - if (elements.count() == 0) { - return Optional.empty(); - } - - return Optional.of(elements.findFirst().get().asObject()); - } - - public void executeDeleteObject(Object key) throws ChampObjectNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Stream<ChampElement> elements = runTraversal(startTraversal().V(key).limit(1)); - - if (elements.count() == 0) { - throw new ChampObjectNotExistsException(); - } - - runTraversal(startTraversal().V(key).drop()); - } - - @Override - public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - //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())); - - 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> traversal = startTraversal().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 { - traversal.has(filter.getKey(), filter.getValue()); - } - } - - if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) { - traversal.hasLabel((String) queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())); - } - - - return runTraversal(traversal).map(element -> { - return element.asObject(); //Safe, since we're only operating on vertices - }); - } - - @Override - public Optional<ChampRelationship> retrieveRelationship(Object key) throws ChampUnmarshallingException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Stream<ChampElement> elements = runTraversal(startTraversal().E(key).limit(1)); - - if (elements.count() == 0) return Optional.empty(); - - return Optional.of(elements.findFirst().get().asRelationship()); - } - - public void executeDeleteRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException { - 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"); - - final Stream<ChampElement> elements = runTraversal(startTraversal().E(relationship.getKey().get()).limit(1)); - - if (elements.count() == 0) { - throw new ChampRelationshipNotExistsException(); - } - - runTraversal(startTraversal().E(relationship.getKey().get()).drop()); - } - - @Override - public Stream<ChampRelationship> retrieveRelationships(ChampObject object) - throws ChampUnmarshallingException, ChampObjectNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Stream<ChampElement> elements = runTraversal(startTraversal().V(object.getKey().get()).limit(1).bothE()); - - return elements.map(element -> { - return element.asRelationship(); //Safe, since we're only operating on edges - }); - } - - @Override - public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - //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())); - - 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> traversal = startTraversal().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 { - traversal.has(filter.getKey(), filter.getValue()); - } - } - - if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) { - traversal.hasLabel((String) queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())); - } - - return runTraversal(traversal).map(element -> { - return element.asRelationship(); //Safe, since we are only operating on edges - }); - } - - @Override - public void executeDeletePartition(ChampPartition graph) { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Object[] objectIds = graph.getChampObjects() - .stream() - .filter(o -> o.getKey().isPresent()) - .map(o -> { return o.getKey().get(); }) - .collect(Collectors.toList()) - .toArray(); - - final Object[] relationshipIds = graph.getChampRelationships() - .stream() - .filter(o -> o.getKey().isPresent()) - .map(o -> { return o.getKey().get(); }) - .collect(Collectors.toList()) - .toArray(); - - runTraversal(startTraversal().V(objectIds).drop()); - runTraversal(startTraversal().E(relationshipIds).drop()); - } - - @Override - protected ChampObject doStoreObject(ChampObject object) - throws ChampMarshallingException, ChampObjectNotExistsException { - final GraphTraversal<Vertex, Vertex> traversal; - - if (object.getKey().isPresent()) { - traversal = startTraversal().V(object.getKey().get()); - } else { - traversal = startTraversal().addV(object.getType()); - } - - for (Entry<String, Object> property : object.getProperties().entrySet()) { - - if (property.getValue() instanceof List) { - for (Object subPropertyValue : (List<?>) property.getValue()) { - traversal.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue); - } - } else if (property.getValue() instanceof Set) { - for (Object subPropertyValue : (Set<?>) property.getValue()) { - traversal.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue); - } - } else { - traversal.property(property.getKey(), property.getValue()); - } - } - - return runTraversal(traversal).findFirst().get().asObject(); //TODO check if this return the updated vertices - } - - @Override - protected ChampObject doReplaceObject(ChampObject object) - throws ChampMarshallingException, ChampObjectNotExistsException { - //TODO: implement the replace method when required - throw new UnsupportedOperationException("Method not implemented"); - } - - @Override - protected ChampRelationship doReplaceRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException, ChampMarshallingException { - //TODO: implement the replace method when required - throw new UnsupportedOperationException("Method not implemented"); - } - - @Override - protected ChampRelationship doStoreRelationship(ChampRelationship relationship) throws ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException { - - /* FIXME: Only compatible with Tinkerpop 3.2.3 (Titan uses 3.0.1-incubating). - - final GraphTraversal<?, Vertex> sourceBuilder; - - if (relationship.getSource().getKey().isPresent()) { - sourceBuilder = startTraversal().V(relationship.getSource().getKey().get()).as("source"); - } else { - sourceBuilder = startTraversal().addV(relationship.getSource().getType()); - } - - for (Entry<String, Object> sourceProperty : relationship.getSource().getProperties().entrySet()) { - sourceBuilder.property(sourceProperty.getKey(), sourceProperty.getValue()); - } - - final GraphTraversal<?, Vertex> targetBuilder; - - if (relationship.getTarget().getKey().isPresent()) { - targetBuilder = sourceBuilder.V(relationship.getTarget().getKey().get()).as("target"); - } else { - targetBuilder = sourceBuilder.addV(relationship.getTarget().getType()); - } - - for (Entry<String, Object> targetProperty : relationship.getTarget().getProperties().entrySet()) { - targetBuilder.property(targetProperty.getKey(), targetProperty.getValue()); - } - - final GraphTraversal<?, Edge> edgeBuilder = targetBuilder.addE(relationship.getType()).from("source"); - - for (Entry<String, Object> property : relationship.getProperties().entrySet()) { - edgeBuilder.property(property.getKey(), property.getValue()); - } - - return runTraversal(edgeBuilder).filter(e -> e.isRelationship()).findFirst().get().asRelationship(); - */ - - throw new UnsupportedOperationException("Cannot store relationships because of project setup (Incompatible Tinkerpop version in use)"); - } - - @Override - protected ChampPartition doStorePartition(ChampPartition submittedPartition) throws ChampObjectNotExistsException, ChampMarshallingException, ChampRelationshipNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - try { - final HashMap<ChampObject, ChampObject> objectsWithKeys = new HashMap<ChampObject, ChampObject> (); - final CreateChampPartitionable storedPartition = ChampPartition.create(); - - for (ChampObject champObject : submittedPartition.getChampObjects()) { - - final ChampObject objectWithKey = doStoreObject(champObject); - objectsWithKeys.put(champObject, objectWithKey); - } - - for (ChampRelationship champRelationship : submittedPartition.getChampRelationships()) { - if (!objectsWithKeys.containsKey(champRelationship.getSource())) { - final ChampObject objectWithKey = doStoreObject(champRelationship.getSource()); - - objectsWithKeys.put(champRelationship.getSource(), objectWithKey); - } - - if (!objectsWithKeys.containsKey(champRelationship.getTarget())) { - final ChampObject objectWithKey = doStoreObject(champRelationship.getTarget()); - - objectsWithKeys.put(champRelationship.getTarget(), objectWithKey); - } - - 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 ChampRelationship relationship = doStoreRelationship(relWithKeysBuilder.build()); - - storedPartition.withRelationship(relationship); - } - - for (ChampObject object : objectsWithKeys.values()) { - storedPartition.withObject(object); - } - - return storedPartition.build(); - } catch (ChampObjectNotExistsException | ChampMarshallingException e) { - throw e; - } - } -} diff --git a/src/main/java/org/onap/aai/champ/graph/impl/AbstractTinkerpopChampGraph.java b/src/main/java/org/onap/aai/champ/graph/impl/AbstractTinkerpopChampGraph.java deleted file mode 100644 index fbe30f7..0000000 --- a/src/main/java/org/onap/aai/champ/graph/impl/AbstractTinkerpopChampGraph.java +++ /dev/null @@ -1,753 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.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.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.champ.event.ChampEvent; -import org.onap.aai.champ.event.ChampEvent.ChampOperation; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.graph.impl.TitanChampGraphImpl.Builder; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.model.fluent.partition.CreateChampPartitionable; -import org.onap.aai.champ.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 static final int COMMIT_RETRY_COUNT = 3; - - 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; - } - - private Vertex writeVertex(ChampObject object) throws ChampObjectNotExistsException, ChampMarshallingException { - final Vertex vertex; - - if (object.getKey().isPresent()) { - final Iterator<Vertex> vertexIter = getGraph().vertices(object.getKey().get()); - - if (vertexIter.hasNext()) { - vertex = vertexIter.next(); - } else throw new ChampObjectNotExistsException(); - } else { - vertex = getGraph().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) throws ChampObjectNotExistsException, ChampMarshallingException { - Vertex vertex; - - if (object.getKey().isPresent()) { - final Iterator<Vertex> vertexIter = getGraph().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) throws ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException { - - final Vertex source = writeVertex(relationship.getSource()); - final Vertex target = writeVertex(relationship.getTarget()); - final Edge edge; - - if (relationship.getKey().isPresent()) { - final Iterator<Edge> edgeIter = getGraph().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) throws ChampRelationshipNotExistsException, ChampMarshallingException { - final Edge edge; - - if(!relationship.getSource().getKey().isPresent() || !relationship.getTarget().getKey().isPresent()){ - throw new IllegalArgumentException("Invalid source/target"); - } - - if (relationship.getKey().isPresent()) { - final Iterator<Edge> edgeIter = getGraph().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; - } - - private void tryRollback() { - if (getGraph().features().graph().supportsTransactions()) { - getGraph().tx().rollback(); - } - } - - private void tryCommit() { - - if (getGraph().features().graph().supportsTransactions()) { - - final long initialBackoff = (int) (Math.random() * 50); - - for (int i = 0; i < COMMIT_RETRY_COUNT; i++) { - try { - getGraph().tx().commit(); - return; - } catch (Throwable e) { - if (i == COMMIT_RETRY_COUNT - 1) { - LOGGER.error("Maxed out commit attempt retries, client must handle exception and retry", e); - getGraph().tx().rollback(); - throw e; - } - - final long backoff = (long) Math.pow(2, i) * initialBackoff; - LOGGER.warn("Caught exception while retrying transaction commit, retrying in " + backoff + " ms"); - - try { - Thread.sleep(backoff); - } catch (InterruptedException ie) { - LOGGER.info("Interrupted while backing off on transaction commit"); - return; - } - } - } - } - } - - 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) { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - //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())); - - 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 = getGraph().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())) { - query.hasLabel((String) 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); - } - } - - tryCommit(); //Danger ahead if this iterator is not completely consumed - //then the transaction cache will hold stale values - - 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 { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Iterator<Vertex> vertices = getGraph().vertices(key); - final Optional<ChampObject> optionalObject; - - if (!vertices.hasNext()) optionalObject = Optional.empty(); - else optionalObject = Optional.of(getChampformer().unmarshallObject(vertices.next())); - - tryCommit(); - - return optionalObject; - } - - @Override - public Stream<ChampRelationship> retrieveRelationships(ChampObject source) throws ChampUnmarshallingException, ChampObjectNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Vertex sourceVertex; - - try { - sourceVertex = getGraph().vertices(source.getKey().get()).next(); - } catch (NoSuchElementException e) { - tryRollback(); - - 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); - } - } - - tryCommit();//Danger ahead if this iterator is not completely - //consumed, then the transaction cache will be stale - 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) throws ChampMarshallingException, ChampObjectNotExistsException { - - try { - final Vertex vertex = writeVertex(object); - - tryCommit(); - - return ChampObject.create() - .from(object) - .withKey(vertex.id()) - .build(); - - } catch (ChampObjectNotExistsException e) { - tryRollback(); - - throw e; - } - } - - @Override - public ChampObject doReplaceObject(ChampObject object) throws ChampMarshallingException, ChampObjectNotExistsException { - - try { - final Vertex vertex = replaceVertex(object); - - tryCommit(); - - return ChampObject.create() - .from(object) - .withKey(vertex.id()) - .build(); - - } catch (ChampObjectNotExistsException e) { - tryRollback(); - - throw e; - } - } - - public void executeDeleteObject(Object key) throws ChampObjectNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Iterator<Vertex> vertex = getGraph().vertices(key); - - if (!vertex.hasNext()) { - tryRollback(); - - throw new ChampObjectNotExistsException(); - } - - vertex.next().remove(); - - tryCommit(); - } - - @Override - public ChampRelationship doStoreRelationship(ChampRelationship relationship) - throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException { - - try { - final Edge edge = writeEdge(relationship); - - tryCommit(); - - return getChampformer().unmarshallRelationship(edge); - - } catch (ChampObjectNotExistsException | ChampRelationshipNotExistsException | ChampUnmarshallingException | ChampMarshallingException e) { - tryRollback(); - - throw e; - } - } - - @Override - public ChampRelationship doReplaceRelationship(ChampRelationship relationship) - throws ChampUnmarshallingException, ChampRelationshipNotExistsException, ChampMarshallingException { - - try { - final Edge edge = replaceEdge(relationship); - - tryCommit(); - - return getChampformer().unmarshallRelationship(edge); - - } catch ( ChampRelationshipNotExistsException | ChampUnmarshallingException | ChampMarshallingException e) { - tryRollback(); - - throw e; - } - } - - @Override - public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - //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())); - - 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 = getGraph().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())) { - query.hasLabel((String) 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); - } - } - - tryCommit(); //Danger ahead if this iterator is not completely - //consumed, then the transaction cache will be stale - - 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 { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - final Iterator<Edge> edge = getGraph().edges(key); - final Optional<ChampRelationship> optionalRelationship; - - if (!edge.hasNext()) optionalRelationship = Optional.empty(); - else optionalRelationship = Optional.of(getChampformer().unmarshallRelationship(edge.next())); - - tryCommit(); - - return optionalRelationship; - } - - public void executeDeleteRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException { - 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"); - - final Iterator<Edge> edge = getGraph().edges(relationship.getKey().get()); - - if (!edge.hasNext()) { - tryRollback(); - - throw new ChampRelationshipNotExistsException(); - } - - edge.next().remove(); - - tryCommit(); - } - - @Override - public ChampPartition doStorePartition(ChampPartition submittedPartition) throws ChampMarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - 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); - 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()); - - objectsWithKeys.put(champRelationship.getSource(), ChampObject.create() - .from(champRelationship.getSource()) - .withKey(vertex.id()) - .build()); - } - - if (!objectsWithKeys.containsKey(champRelationship.getTarget())) { - final Vertex vertex = writeVertex(champRelationship.getTarget()); - - 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()); - - storedPartition.withRelationship(ChampRelationship.create() - .from(champRelationship) - .withKey(edge.id()) - .build()); - } - - for (ChampObject object : objectsWithKeys.values()) { - storedPartition.withObject(object); - } - - tryCommit(); - - return storedPartition.build(); - - } catch (ChampObjectNotExistsException | ChampMarshallingException e) { - tryRollback(); - - throw e; - } - } - - public void executeDeletePartition(ChampPartition graph) { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - for (ChampObject champObject : graph.getChampObjects()) { - try { - final Object vertexId = champObject.getKey().get(); - final Iterator<Vertex> vertex = getGraph().vertices(vertexId); - - if (vertex.hasNext()) { - vertex.next().remove(); - } - } catch (NoSuchElementException e) { - tryRollback(); - - throw new IllegalArgumentException("Must pass a key to delete an object"); - } - } - - for (ChampRelationship champRelationship : graph.getChampRelationships()) { - try { - final Iterator<Edge> edge = getGraph().edges(champRelationship.getKey().get()); - - if (edge.hasNext()) { - edge.next().remove(); - } - } catch (NoSuchElementException e) { - tryRollback(); - - throw new IllegalArgumentException("Must pass a key to delete a relationship"); - } - } - - tryCommit(); - - } - - @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(); - } - } -} diff --git a/src/main/java/org/onap/aai/champ/graph/impl/AbstractValidatingChampGraph.java b/src/main/java/org/onap/aai/champ/graph/impl/AbstractValidatingChampGraph.java deleted file mode 100644 index a4161df..0000000 --- a/src/main/java/org/onap/aai/champ/graph/impl/AbstractValidatingChampGraph.java +++ /dev/null @@ -1,176 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.graph.impl; - -import java.util.Map; -import java.util.Optional; - -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.event.AbstractLoggingChampGraph; -import org.onap.aai.champ.event.ChampEvent; -import org.onap.aai.champ.event.ChampEvent.ChampOperation; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.graph.impl.TitanChampGraphImpl.Builder; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.schema.ChampSchemaEnforcer; - -public abstract class AbstractValidatingChampGraph extends AbstractLoggingChampGraph { - - private ChampSchema schema = ChampSchema.emptySchema(); - - protected abstract ChampSchemaEnforcer getSchemaEnforcer(); - protected abstract boolean isShutdown(); - - protected abstract ChampObject doReplaceObject(ChampObject object) throws ChampMarshallingException, ChampObjectNotExistsException; - protected abstract ChampObject doStoreObject(ChampObject object) throws ChampMarshallingException, ChampObjectNotExistsException; - protected abstract ChampRelationship doReplaceRelationship(ChampRelationship relationship) throws ChampUnmarshallingException, ChampRelationshipNotExistsException, ChampMarshallingException; - protected abstract ChampRelationship doStoreRelationship(ChampRelationship relationship) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException; - protected abstract ChampPartition doStorePartition(ChampPartition partition) throws ChampRelationshipNotExistsException, ChampMarshallingException, ChampObjectNotExistsException; - - protected AbstractValidatingChampGraph(Map<String, Object> properties) { - super(properties); - } - - public ChampObject executeStoreObject(ChampObject object) - throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - validate(object); - - return doStoreObject(object); - } - - public ChampObject executeReplaceObject(ChampObject object) - throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - validate(object); - - return doReplaceObject(object); - } - - public ChampRelationship executeStoreRelationship(ChampRelationship relationship) - throws ChampUnmarshallingException, ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, ChampRelationshipNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - validate(relationship); - - return doStoreRelationship(relationship); - } - - public ChampRelationship executeReplaceRelationship(ChampRelationship relationship) - throws ChampUnmarshallingException, ChampMarshallingException, ChampSchemaViolationException, ChampRelationshipNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - validate(relationship); - - return doReplaceRelationship(relationship); - } - - public ChampPartition executeStorePartition(ChampPartition partition) throws ChampSchemaViolationException, ChampRelationshipNotExistsException, ChampMarshallingException, ChampObjectNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()"); - - validate(partition); - - return doStorePartition(partition); - } - - 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/src/main/java/org/onap/aai/champ/graph/impl/TitanChampGraphImpl.java b/src/main/java/org/onap/aai/champ/graph/impl/TitanChampGraphImpl.java deleted file mode 100644 index 73f24a5..0000000 --- a/src/main/java/org/onap/aai/champ/graph/impl/TitanChampGraphImpl.java +++ /dev/null @@ -1,458 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.graph.impl; - -import com.thinkaurelius.titan.core.Cardinality; -import com.thinkaurelius.titan.core.EdgeLabel; -import com.thinkaurelius.titan.core.PropertyKey; -import com.thinkaurelius.titan.core.SchemaViolationException; -import com.thinkaurelius.titan.core.TitanEdge; -import com.thinkaurelius.titan.core.TitanFactory; -import com.thinkaurelius.titan.core.TitanGraph; -import com.thinkaurelius.titan.core.TitanVertex; -import com.thinkaurelius.titan.core.schema.SchemaAction; -import com.thinkaurelius.titan.core.schema.SchemaStatus; -import com.thinkaurelius.titan.core.schema.TitanGraphIndex; -import com.thinkaurelius.titan.core.schema.TitanManagement; -import com.thinkaurelius.titan.graphdb.database.management.ManagementSystem; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.onap.aai.champ.ChampCapabilities; -import org.onap.aai.champ.exceptions.ChampIndexNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.model.ChampCardinality; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampObjectIndex; -import org.onap.aai.champ.model.ChampPropertyConstraint; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipConstraint; -import org.onap.aai.champ.model.ChampRelationshipIndex; -import org.onap.aai.champ.model.ChampSchema; -import org.onap.aai.champ.schema.ChampSchemaEnforcer; -import org.onap.aai.champ.schema.DefaultChampSchemaEnforcer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.time.temporal.ChronoUnit; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.concurrent.ExecutionException; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -public final class TitanChampGraphImpl extends AbstractTinkerpopChampGraph { - - private static final Logger LOGGER = LoggerFactory.getLogger(TitanChampGraphImpl.class); - private static final String TITAN_CASSANDRA_KEYSPACE = "storage.cassandra.keyspace"; - private static final String TITAN_HBASE_TABLE = "storage.hbase.table"; - private static final ChampSchemaEnforcer SCHEMA_ENFORCER = new DefaultChampSchemaEnforcer(); - private static final int REGISTER_OBJECT_INDEX_TIMEOUT_SECS = 30; - - private static final ChampCapabilities CAPABILITIES = new ChampCapabilities() { - - @Override - public boolean canDeleteObjectIndices() { - return false; - } - - @Override - public boolean canDeleteRelationshipIndices() { - return false; - } - }; - - private final TitanGraph graph; - - private TitanChampGraphImpl(Builder builder) { - super(builder.graphConfiguration); - final TitanFactory.Builder titanGraphBuilder = TitanFactory.build(); - - for (Entry<String, Object> titanGraphProperty : builder.graphConfiguration.entrySet()) { - titanGraphBuilder.set(titanGraphProperty.getKey(), titanGraphProperty.getValue()); - } - - final Object storageBackend = builder.graphConfiguration.get("storage.backend"); - - if ("cassandra".equals(storageBackend) || "cassandrathrift".equals(storageBackend) - || "astyanax".equals(storageBackend) || "embeddedcassandra".equals(storageBackend)) { - titanGraphBuilder.set(TITAN_CASSANDRA_KEYSPACE, builder.graphName); - } else if ("hbase".equals(storageBackend)) { - titanGraphBuilder.set(TITAN_HBASE_TABLE, builder.graphName); - } else if ("berkleyje".equals(storageBackend)) { - throw new RuntimeException("storage.backend=berkleyje cannot handle multiple graphs on a single DB, not usable"); - } else if ("inmemory".equals(storageBackend)) { - } else { - throw new RuntimeException("Unknown storage.backend=" + storageBackend); - } - - this.graph = titanGraphBuilder.open(); - } - - public static class Builder { - private final String graphName; - - private final Map<String, Object> graphConfiguration = new HashMap<String, Object> (); - - public Builder(String graphName) { - this.graphName = graphName; - } - - public Builder properties(Map<String, Object> properties) { - if (properties.containsKey(TITAN_CASSANDRA_KEYSPACE)) - throw new IllegalArgumentException("Cannot use path " + TITAN_CASSANDRA_KEYSPACE - + " in initial configuration - this path is used" - + " to specify graph names"); - - this.graphConfiguration.putAll(properties); - return this; - } - - public Builder property(String path, Object value) { - if (path.equals(TITAN_CASSANDRA_KEYSPACE)) - throw new IllegalArgumentException("Cannot use path " + TITAN_CASSANDRA_KEYSPACE - + " in initial configuration - this path is used" - + " to specify graph names"); - graphConfiguration.put(path, value); - return this; - } - - public TitanChampGraphImpl build() { - return new TitanChampGraphImpl(this); - } - } - - @Override - protected TitanGraph getGraph() { - return graph; - } - - @Override - protected ChampSchemaEnforcer getSchemaEnforcer() { - return SCHEMA_ENFORCER; - } - - public void executeStoreObjectIndex(ChampObjectIndex index) { - if (isShutdown()) throw new IllegalStateException("Cannot call storeObjectIndex() after shutdown has been initiated"); - - final TitanGraph graph = getGraph(); - final TitanManagement createIndexMgmt = graph.openManagement(); - final PropertyKey pk = createIndexMgmt.getOrCreatePropertyKey(index.getField().getName()); - - if (createIndexMgmt.getGraphIndex(index.getName()) != null) { - createIndexMgmt.rollback(); - return; //Ignore, index already exists - } - - createIndexMgmt.buildIndex(index.getName(), Vertex.class).addKey(pk).buildCompositeIndex(); - - createIndexMgmt.commit(); - graph.tx().commit(); - - awaitIndexCreation(index.getName()); - } - - @Override - public Optional<ChampObjectIndex> retrieveObjectIndex(String indexName) { - if (isShutdown()) throw new IllegalStateException("Cannot call retrieveObjectIndex() after shutdown has been initiated"); - - final TitanManagement retrieveIndexMgmt = getGraph().openManagement(); - final TitanGraphIndex index = retrieveIndexMgmt.getGraphIndex(indexName); - - if (index == null) return Optional.empty(); - if (index.getIndexedElement() != TitanVertex.class) return Optional.empty(); - - return Optional.of(ChampObjectIndex.create() - .ofName(indexName) - .onType(ChampObject.ReservedTypes.ANY.toString()) - .forField(index.getFieldKeys()[0].name()) - .build()); - } - - @Override - public Stream<ChampObjectIndex> retrieveObjectIndices() { - if (isShutdown()) throw new IllegalStateException("Cannot call retrieveObjectIndices() after shutdown has been initiated"); - - final TitanManagement createIndexMgmt = getGraph().openManagement(); - final Iterator<TitanGraphIndex> indices = createIndexMgmt.getGraphIndexes(Vertex.class).iterator(); - - final Iterator<ChampObjectIndex> objIter = new Iterator<ChampObjectIndex> () { - - private ChampObjectIndex next; - - @Override - public boolean hasNext() { - if (indices.hasNext()) { - final TitanGraphIndex index = indices.next(); - - next = ChampObjectIndex.create() - .ofName(index.name()) - .onType(ChampObject.ReservedTypes.ANY.toString()) - .forField(index.getFieldKeys()[0].name()) - .build(); - return true; - } - - next = null; - return false; - } - - @Override - public ChampObjectIndex next() { - if (next == null) throw new NoSuchElementException(); - - return next; - } - }; - - return StreamSupport.stream(Spliterators.spliteratorUnknownSize( - objIter, Spliterator.ORDERED | Spliterator.NONNULL), false); - } - - public void executeDeleteObjectIndex(String indexName) throws ChampIndexNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot call deleteObjectIndex() after shutdown has been initiated"); - - throw new UnsupportedOperationException("Cannot delete indices using the TitanChampImpl"); - } - - public void executeStoreRelationshipIndex(ChampRelationshipIndex index) { - if (isShutdown()) throw new IllegalStateException("Cannot call storeRelationshipIndex() after shutdown has been initiated"); - - final TitanGraph graph = getGraph(); - final TitanManagement createIndexMgmt = graph.openManagement(); - final PropertyKey pk = createIndexMgmt.getOrCreatePropertyKey(index.getField().getName()); - - if (createIndexMgmt.getGraphIndex(index.getName()) != null) return; //Ignore, index already exists - createIndexMgmt.buildIndex(index.getName(), Edge.class).addKey(pk).buildCompositeIndex(); - - createIndexMgmt.commit(); - graph.tx().commit(); - - awaitIndexCreation(index.getName()); - } - - @Override - public Optional<ChampRelationshipIndex> retrieveRelationshipIndex(String indexName) { - if (isShutdown()) throw new IllegalStateException("Cannot call retrieveRelationshipIndex() after shutdown has been initiated"); - - final TitanManagement retrieveIndexMgmt = getGraph().openManagement(); - final TitanGraphIndex index = retrieveIndexMgmt.getGraphIndex(indexName); - - if (index == null) return Optional.empty(); - if (index.getIndexedElement() != TitanEdge.class) return Optional.empty(); - - return Optional.of(ChampRelationshipIndex.create() - .ofName(indexName) - .onType(ChampObject.ReservedTypes.ANY.toString()) - .forField(index.getFieldKeys()[0].name()) - .build()); - } - - @Override - public Stream<ChampRelationshipIndex> retrieveRelationshipIndices() { - if (isShutdown()) throw new IllegalStateException("Cannot call retrieveRelationshipIndices() after shutdown has been initiated"); - - final TitanManagement createIndexMgmt = getGraph().openManagement(); - final Iterator<TitanGraphIndex> indices = createIndexMgmt.getGraphIndexes(Edge.class).iterator(); - - final Iterator<ChampRelationshipIndex> objIter = new Iterator<ChampRelationshipIndex> () { - - private ChampRelationshipIndex next; - - @Override - public boolean hasNext() { - if (indices.hasNext()) { - final TitanGraphIndex index = indices.next(); - - next = ChampRelationshipIndex.create() - .ofName(index.name()) - .onType(ChampRelationship.ReservedTypes.ANY.toString()) - .forField(index.getFieldKeys()[0].name()) - .build(); - return true; - } - - next = null; - return false; - } - - @Override - public ChampRelationshipIndex next() { - if (next == null) throw new NoSuchElementException(); - - return next; - } - }; - - return StreamSupport.stream(Spliterators.spliteratorUnknownSize( - objIter, Spliterator.ORDERED | Spliterator.NONNULL), false); - } - - public void executeDeleteRelationshipIndex(String indexName) throws ChampIndexNotExistsException { - if (isShutdown()) throw new IllegalStateException("Cannot call deleteRelationshipIndex() after shutdown has been initiated"); - - throw new UnsupportedOperationException("Cannot delete indices using the TitanChampImpl"); - } - - private Cardinality getTitanCardinality(ChampCardinality cardinality) { - switch (cardinality) { - case LIST: - return Cardinality.LIST; - case SET: - return Cardinality.SET; - case SINGLE: - return Cardinality.SINGLE; - default: - throw new RuntimeException("Unknown ChampCardinality " + cardinality); - } - } - - private void awaitIndexCreation(String indexName) { - //Wait for the index to become available - try { - if (ManagementSystem.awaitGraphIndexStatus(graph, indexName) - .status(SchemaStatus.ENABLED) - .timeout(1, ChronoUnit.SECONDS) - .call() - .getSucceeded()) { - return; //Empty graphs immediately ENABLE indices - } - - if (!ManagementSystem.awaitGraphIndexStatus(graph, indexName) - .status(SchemaStatus.REGISTERED) - .timeout(REGISTER_OBJECT_INDEX_TIMEOUT_SECS, ChronoUnit.SECONDS) - .call() - .getSucceeded()) { - LOGGER.warn("Object index was created, but timed out while waiting for it to be registered"); - return; - } - } catch (InterruptedException e) { - LOGGER.warn("Interrupted while waiting for object index creation status"); - return; - } - - //Reindex the existing data - - try { - final TitanManagement updateIndexMgmt = graph.openManagement(); - updateIndexMgmt.updateIndex(updateIndexMgmt.getGraphIndex(indexName),SchemaAction.REINDEX).get(); - updateIndexMgmt.commit(); - } catch (InterruptedException e) { - LOGGER.warn("Interrupted while reindexing for object index"); - return; - } catch (ExecutionException e) { - LOGGER.warn("Exception occurred during reindexing procedure for creating object index " + indexName, e); - } - - try { - ManagementSystem.awaitGraphIndexStatus(graph, indexName) - .status(SchemaStatus.ENABLED) - .timeout(10, ChronoUnit.MINUTES) - .call(); - } catch (InterruptedException e) { - LOGGER.warn("Interrupted while waiting for index to transition to ENABLED state"); - return; - } - } - - @Override - public ChampCapabilities capabilities() { - return CAPABILITIES; - } - - @Override - public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException { - if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated"); - - final ChampSchema currentSchema = retrieveSchema(); - final TitanManagement mgmt = getGraph().openManagement(); - - try { - for (ChampObjectConstraint objConstraint : schema.getObjectConstraints().values()) { - for (ChampPropertyConstraint propConstraint : objConstraint.getPropertyConstraints()) { - final Optional<ChampObjectConstraint> currentObjConstraint = currentSchema.getObjectConstraint(objConstraint.getType()); - - if (currentObjConstraint.isPresent()) { - final Optional<ChampPropertyConstraint> currentPropConstraint = currentObjConstraint.get().getPropertyConstraint(propConstraint.getField().getName()); - - if (currentPropConstraint.isPresent() && currentPropConstraint.get().compareTo(propConstraint) != 0) { - throw new ChampSchemaViolationException("Cannot update already existing property on object type " + objConstraint.getType() + ": " + propConstraint); - } - } - - final String newPropertyKeyName = propConstraint.getField().getName(); - - if (mgmt.getPropertyKey(newPropertyKeyName) != null) continue; //Check Titan to see if another node created this property key - - mgmt.makePropertyKey(newPropertyKeyName) - .dataType(propConstraint.getField().getJavaType()) - .cardinality(getTitanCardinality(propConstraint.getCardinality())) - .make(); - } - } - - for (ChampRelationshipConstraint relConstraint : schema.getRelationshipConstraints().values()) { - - final Optional<ChampRelationshipConstraint> currentRelConstraint = currentSchema.getRelationshipConstraint(relConstraint.getType()); - - for (ChampPropertyConstraint propConstraint : relConstraint.getPropertyConstraints()) { - - if (currentRelConstraint.isPresent()) { - final Optional<ChampPropertyConstraint> currentPropConstraint = currentRelConstraint.get().getPropertyConstraint(propConstraint.getField().getName()); - - if (currentPropConstraint.isPresent() && currentPropConstraint.get().compareTo(propConstraint) != 0) { - throw new ChampSchemaViolationException("Cannot update already existing property on relationship type " + relConstraint.getType()); - } - } - - final String newPropertyKeyName = propConstraint.getField().getName(); - - if (mgmt.getPropertyKey(newPropertyKeyName) != null) continue; //Check Titan to see if another node created this property key - - mgmt.makePropertyKey(newPropertyKeyName) - .dataType(propConstraint.getField().getJavaType()) - .cardinality(getTitanCardinality(propConstraint.getCardinality())) - .make(); - } - - final EdgeLabel edgeLabel = mgmt.getEdgeLabel(relConstraint.getType()); - - if (edgeLabel != null) mgmt.makeEdgeLabel(relConstraint.getType()) - .directed() - .make(); - } - - mgmt.commit(); - - super.storeSchema(schema); - } catch (SchemaViolationException | ChampSchemaViolationException e) { - mgmt.rollback(); - throw new ChampSchemaViolationException(e); - } - } -} diff --git a/src/main/java/org/onap/aai/champ/model/ChampObject.java b/src/main/java/org/onap/aai/champ/model/ChampObject.java deleted file mode 100644 index 9593ef1..0000000 --- a/src/main/java/org/onap/aai/champ/model/ChampObject.java +++ /dev/null @@ -1,239 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.model; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.onap.aai.champ.model.fluent.object.CreateChampObjectable; -import org.onap.aai.champ.model.fluent.object.impl.CreateChampObjectableImpl; - -import java.util.Optional; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -public final class ChampObject implements ChampElement { - - private final String type; - private final Optional<Object> key; - private final Map<String, Object> properties; - - public static CreateChampObjectable create() { - return new CreateChampObjectableImpl(); - } - - private ChampObject() { - throw new RuntimeException("Attempted to call private AAIObject() constructor"); - } //Not instantiable - - 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 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/src/test/java/org/onap/aai/champ/concurrency/ConcurrencyTest.java b/src/test/java/org/onap/aai/champ/concurrency/ConcurrencyTest.java deleted file mode 100644 index f33266d..0000000 --- a/src/test/java/org/onap/aai/champ/concurrency/ConcurrencyTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.concurrency; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.core.ChampObjectTest; -import org.onap.aai.champ.core.ChampRelationshipTest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConcurrencyTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrencyTest.class); - - @Test - public void runConcurrentTest() { - for (ChampGraph.Type apiType : ChampGraph.Type.values()) { - 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/src/test/java/org/onap/aai/champ/core/ChampAPITest.java b/src/test/java/org/onap/aai/champ/core/ChampAPITest.java deleted file mode 100644 index d0097d9..0000000 --- a/src/test/java/org/onap/aai/champ/core/ChampAPITest.java +++ /dev/null @@ -1,239 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.core; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.model.ChampObjectConstraint; -import org.onap.aai.champ.model.ChampRelationshipConstraint; - -public class ChampAPITest { - - @Test - public void testChampAPIInstantiation() { - - for (ChampGraph.Type type : ChampGraph.Type.values()) { - - final ChampAPI api = ChampAPI.Factory.newInstance(type); - - assertTrue(type == ChampGraph.Type.valueOf(type.name())); - assertTrue(api.getType() == type); - - 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 testChampGraphInstantiation() throws Exception { - for (ChampGraph.Type type : ChampGraph.Type.values()) { - final ChampGraph graph = ChampGraph.Factory.newInstance(type, "foo"); - - graph.shutdown(); - - try { - graph.deleteObject(null); - 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); - throw new AssertionError("Able to call API method after shutdown was initiated"); - } catch (IllegalStateException e) { - //Expected - } - - try { - graph.deleteRelationship(null); - 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); - throw new AssertionError("Able to call API method after shutdown was initiated"); - } catch (IllegalStateException e) { - //Expected - } - - try { - graph.queryRelationships(null); - throw new AssertionError("Able to call API method after shutdown was initiated"); - } catch (IllegalStateException e) { - //Expected - } - - try { - graph.retrieveObject(null); - 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); - 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); - 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); - 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); - throw new AssertionError("Able to call API method after shutdown was initiated"); - } catch (IllegalStateException e) { - //Expected - } - - try { - graph.storeRelationship(null); - 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/src/test/java/org/onap/aai/champ/core/ChampObjectTest.java b/src/test/java/org/onap/aai/champ/core/ChampObjectTest.java deleted file mode 100644 index fea167b..0000000 --- a/src/test/java/org/onap/aai/champ/core/ChampObjectTest.java +++ /dev/null @@ -1,331 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.core; - -import static org.junit.Assert.assertTrue; - -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 org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampCardinality; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampSchema; - -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 runTest() { - for (ChampGraph.Type apiType : ChampGraph.Type.values()) { - final String graphName = ChampObjectTest.class.getSimpleName(); - switch (apiType) { - case TITAN: - cleanUp(graphName); - break; - default: - break; - } - - final ChampAPI api = ChampAPI.Factory.newInstance(apiType); - ChampObjectTest.testChampObjectCrud(api.getGraph(graphName)); - testChampObjectReservedProperties(api.getGraph(graphName)); - api.shutdown(); - } - } - - public static void testChampObjectCrud(ChampGraph graph) { - 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 { - - 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()); - - storedBookooObject = graph.storeObject(bookooObject); - - 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()); - final Stream<ChampObject> emptyStream = graph.queryObjects(new HashMap<String, Object> () {{ - put(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString(), "foo"); - put("long", 2L); - }}); - - 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); - }}); - 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())) - .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()); - - final Optional<ChampObject> retrievedUpdBookooObject = graph.retrieveObject(updatedBookoo.getKey().get()); - - 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()); - - final Optional<ChampObject> retrievedReplacedBookooObject = graph.retrieveObject(replacedBookoo.getKey().get()); - - 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()); - if (graph.retrieveObject(storedBookooObject.getKey().get()).isPresent()) throw new AssertionError("Object not successfully deleted"); - - assertTrue(graph.queryObjects(Collections.emptyMap()).count() == 0); - assertTrue(graph.queryRelationships(Collections.emptyMap()).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); - } - - try { - graph.deleteObject(storedBookooObject.getKey().get()); - throw new AssertionError("Delete succeeded when it should have failed"); - } catch (ChampObjectNotExistsException e) { - //Expected - } - - try { - graph.storeObject(ChampObject.create() - .ofType("foo") - .withKey("non-existent object key") - .build()); - 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); - } - - try { - // validate the replaceObject method when Object key is not passed - graph.replaceObject( - ChampObject.create().ofType("foo").withoutKey().withProperty("property1", "value2").build()); - } catch (ChampObjectNotExistsException e) { - // Expected - } catch (ChampMarshallingException e) { - throw new AssertionError(e); - } catch (ChampSchemaViolationException 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/src/test/java/org/onap/aai/champ/core/ChampPartitionTest.java b/src/test/java/org/onap/aai/champ/core/ChampPartitionTest.java deleted file mode 100644 index 42894f4..0000000 --- a/src/test/java/org/onap/aai/champ/core/ChampPartitionTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.core; - -import static org.junit.Assert.assertTrue; - -import java.util.Collections; -import java.util.Optional; - -import org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampPartition; -import org.onap.aai.champ.model.ChampRelationship; - -public class ChampPartitionTest extends BaseChampAPITest { - - @Test - public void runTests() { - for (ChampGraph.Type apiType : ChampGraph.Type.values()) { - final ChampAPI api = ChampAPI.Factory.newInstance(apiType); - final String graphName = ChampPartitionTest.class.getSimpleName(); - - switch (apiType) { - case IN_MEMORY: - break; - case TITAN: - cleanUp(graphName); - break; - default: - break; - } - - ChampPartitionTest.testChampPartitionCrud(api.getGraph(graphName)); - api.shutdown(); - } - } - - @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); - } - } - - 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 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 e) { - throw new AssertionError(e); - } - } - } -} diff --git a/src/test/java/org/onap/aai/champ/core/ChampRelationshipIndexTest.java b/src/test/java/org/onap/aai/champ/core/ChampRelationshipIndexTest.java deleted file mode 100644 index 58c7d79..0000000 --- a/src/test/java/org/onap/aai/champ/core/ChampRelationshipIndexTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.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.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampIndexNotExistsException; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampField; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationshipIndex; - -public class ChampRelationshipIndexTest extends BaseChampAPITest { - - @Test - public void runTest() { - for (ChampGraph.Type apiType : ChampGraph.Type.values()) { - final String graphName = ChampRelationshipIndexTest.class.getSimpleName(); - - switch (apiType) { - case IN_MEMORY: - break; - case TITAN: - cleanUp(graphName); - break; - default: - break; - } - - final ChampAPI api = ChampAPI.Factory.newInstance(apiType); - testChampRelationshipIndexCrud(api.getGraph(graphName)); - api.shutdown(); - } - } - - private 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()); - 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); - } - } - - 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/src/test/java/org/onap/aai/champ/core/ChampRelationshipTest.java b/src/test/java/org/onap/aai/champ/core/ChampRelationshipTest.java deleted file mode 100644 index 3d95268..0000000 --- a/src/test/java/org/onap/aai/champ/core/ChampRelationshipTest.java +++ /dev/null @@ -1,261 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - */ -package org.onap.aai.champ.core; - -import static org.junit.Assert.assertTrue; - -import java.util.Collections; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.junit.Test; -import org.onap.aai.champ.ChampAPI; -import org.onap.aai.champ.ChampGraph; -import org.onap.aai.champ.exceptions.ChampMarshallingException; -import org.onap.aai.champ.exceptions.ChampObjectNotExistsException; -import org.onap.aai.champ.exceptions.ChampRelationshipNotExistsException; -import org.onap.aai.champ.exceptions.ChampSchemaViolationException; -import org.onap.aai.champ.exceptions.ChampUnmarshallingException; -import org.onap.aai.champ.model.ChampObject; -import org.onap.aai.champ.model.ChampRelationship; -import org.onap.aai.champ.model.ChampRelationship.ReservedPropertyKeys; -import org.onap.aai.champ.model.ChampRelationship.ReservedTypes; - -public class ChampRelationshipTest extends BaseChampAPITest { - - @Test - public void runTest() { - for (ChampGraph.Type apiType : ChampGraph.Type.values()) { - final String graphName = ChampRelationshipTest.class.getSimpleName(); - - switch (apiType) { - case IN_MEMORY: - break; - case TITAN: - cleanUp(graphName); - break; - default: - break; - } - - 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 { - final ChampObject storedSource = graph.storeObject(source); - final ChampObject storedTarget = graph.storeObject(target); - - 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); - final Optional<ChampRelationship> retrievedRelationship = graph.retrieveRelationship(storedRelationship.getKey().get()); - - 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()).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); - final Optional<ChampRelationship> retrievedUpdRel = graph.retrieveRelationship(storedUpdRel.getKey().get()); - - 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); - final Optional<ChampRelationship> retrievedReplacedRel = graph - .retrieveRelationship(replacedRel.getKey().get()); - - 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()); - - if (graph.retrieveRelationship(relationship.getKey()).isPresent()) throw new AssertionError("Relationship not successfully deleted"); - - try { - graph.deleteRelationship(retrievedRelationship.get()); - throw new AssertionError("Failed to throw exception for missing relationship"); - } catch (ChampRelationshipNotExistsException e) { - //Expected - } - - assertTrue(graph.queryRelationships(Collections.emptyMap()).count() == 0); - assertTrue(graph.queryObjects(Collections.emptyMap()).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); - } - - try { - graph.retrieveRelationships(ChampObject.create().ofType("").withoutKey().build()); - throw new AssertionError("Failed to handle missing object while retrieving relationships"); - } catch (ChampUnmarshallingException 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()); - } - 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 - } - - 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()); - } - 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); - } - - - } - - @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(); - - 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); - } - } -} diff --git a/version.properties b/version.properties index abe15cf..9c95207 100644 --- a/version.properties +++ b/version.properties @@ -4,11 +4,11 @@ # because they are used in Jenkins, whose plug-in doesn't support major_version=1 -minor_version=1 +minor_version=2 patch_version=0 base_version=${major_version}.${minor_version}.${patch_version} # Release must be completed with GIT information # in Jenkins release_version=${base_version} -snapshot_version=${base_version}-SNAPSHOT
\ No newline at end of file +snapshot_version=${base_version}-SNAPSHOT |