2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017 Amdocs
7 * ===================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END============================================
20 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 package org.onap.aai.champcore.graph.impl;
24 import java.io.IOException;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
29 import java.util.Map.Entry;
30 import java.util.NoSuchElementException;
31 import java.util.Optional;
33 import java.util.Spliterator;
34 import java.util.Spliterators;
35 import java.util.Vector;
36 import java.util.concurrent.atomic.AtomicBoolean;
37 import java.util.stream.Stream;
38 import java.util.stream.StreamSupport;
40 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
41 import org.apache.tinkerpop.gremlin.structure.Direction;
42 import org.apache.tinkerpop.gremlin.structure.Edge;
43 import org.apache.tinkerpop.gremlin.structure.Graph;
44 import org.apache.tinkerpop.gremlin.structure.Property;
45 import org.apache.tinkerpop.gremlin.structure.Vertex;
46 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
47 import org.onap.aai.champcore.ChampTransaction;
48 import org.onap.aai.champcore.NoOpTinkerPopTransaction;
49 import org.onap.aai.champcore.exceptions.ChampMarshallingException;
50 import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
51 import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
52 import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
53 import org.onap.aai.champcore.exceptions.ChampTransactionException;
54 import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
55 import org.onap.aai.champcore.model.ChampObject;
56 import org.onap.aai.champcore.model.ChampPartition;
57 import org.onap.aai.champcore.model.ChampRelationship;
58 import org.onap.aai.champcore.model.ChampSchema;
59 import org.onap.aai.champcore.model.fluent.partition.CreateChampPartitionable;
60 import org.onap.aai.champcore.transform.TinkerpopChampformer;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
64 import com.fasterxml.jackson.core.JsonProcessingException;
65 import com.fasterxml.jackson.databind.ObjectMapper;
67 public abstract class AbstractTinkerpopChampGraph extends AbstractValidatingChampGraph {
69 private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTinkerpopChampGraph.class);
70 private static final TinkerpopChampformer TINKERPOP_CHAMPFORMER = new TinkerpopChampformer();
71 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
73 private volatile AtomicBoolean isShutdown;
75 protected AbstractTinkerpopChampGraph(Map<String, Object> properties) {
78 isShutdown = new AtomicBoolean(false);
79 Runtime.getRuntime().addShutdownHook(shutdownHook);
82 private static final TinkerpopChampformer getChampformer() {
83 return TINKERPOP_CHAMPFORMER;
86 private static final ObjectMapper getObjectMapper() {
90 public abstract GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type);
92 public ChampTransaction openTransaction() {
94 return new TinkerpopTransaction(getGraph());
97 private Vertex writeVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
100 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
102 if (object.getKey().isPresent()) {
103 final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
105 if (vertexIter.hasNext()) {
106 vertex = vertexIter.next();
107 } else throw new ChampObjectNotExistsException();
109 vertex = graphInstance.addVertex(object.getType());
112 for (Entry<String, Object> property : object.getProperties().entrySet()) {
114 if (property.getValue() instanceof List) {
115 for (Object subPropertyValue : (List<?>) property.getValue()) {
116 vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
118 } else if (property.getValue() instanceof Set) {
119 for (Object subPropertyValue : (Set<?>) property.getValue()) {
120 vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
123 vertex.property(property.getKey(), property.getValue());
130 private Vertex replaceVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
133 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
135 if (object.getKey().isPresent()) {
136 final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
138 if (vertexIter.hasNext()) {
139 vertex = vertexIter.next();
140 } else throw new ChampObjectNotExistsException();
142 throw new ChampObjectNotExistsException();
145 //clear all the existing properties
146 Iterator<VertexProperty<Object>> it = vertex.properties();
147 while (it.hasNext()) {
151 for (Entry<String, Object> property : object.getProperties().entrySet()) {
153 if (property.getValue() instanceof List) {
154 for (Object subPropertyValue : (List<?>) property.getValue()) {
155 vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
157 } else if (property.getValue() instanceof Set) {
158 for (Object subPropertyValue : (Set<?>) property.getValue()) {
159 vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
162 vertex.property(property.getKey(), property.getValue());
169 private Edge writeEdge(ChampRelationship relationship, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException {
171 final Vertex source = writeVertex(relationship.getSource(), transaction);
172 final Vertex target = writeVertex(relationship.getTarget(), transaction);
175 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
177 if (relationship.getKey().isPresent()) {
178 final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
180 if (edgeIter.hasNext()) {
181 edge = edgeIter.next();
182 } else throw new ChampRelationshipNotExistsException();
184 edge = source.addEdge(relationship.getType(), target);
187 for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
188 edge.property(property.getKey(), property.getValue());
194 private Edge replaceEdge(ChampRelationship relationship, ChampTransaction tx) throws ChampRelationshipNotExistsException, ChampMarshallingException {
196 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
198 if(!relationship.getSource().getKey().isPresent() || !relationship.getTarget().getKey().isPresent()){
199 throw new IllegalArgumentException("Invalid source/target");
202 if (relationship.getKey().isPresent()) {
203 final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
206 if (edgeIter.hasNext()) {
207 edge = edgeIter.next();
208 //validate if the source/target are the same as before. Throw error if not the same
209 if (!edge.outVertex().id().equals(relationship.getSource().getKey().get())
210 || !edge.inVertex().id().equals(relationship.getTarget().getKey().get())) {
211 throw new IllegalArgumentException("source/target can't be updated");
214 } else throw new ChampRelationshipNotExistsException();
216 throw new ChampRelationshipNotExistsException();
219 // clear all the existing properties
220 Iterator<Property<Object>> it = edge.properties();
221 while (it.hasNext()) {
225 for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
226 edge.property(property.getKey(), property.getValue());
233 protected abstract Graph getGraph();
237 private Thread shutdownHook = new Thread() {
242 } catch (IllegalStateException e) {
243 //Suppress, because shutdown() has already been called
248 protected boolean isShutdown() {
249 return isShutdown.get();
253 public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) throws ChampTransactionException {
254 return queryObjects(queryParams, Optional.empty());
259 public Stream<ChampObject> queryObjects(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
262 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
265 // If we were not provided a transaction object then automatically open a transaction
267 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
269 // Use the graph instance associated with our transaction.
270 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
272 //If they provided the object key, do this the quick way rather than creating a traversal
273 if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString())) {
276 final Optional<ChampObject> object =
277 retrieveObject(queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString()),
280 if (object.isPresent()) {
281 return Stream.of(object.get());
283 return Stream.empty();
285 } catch (ChampUnmarshallingException e) {
286 LOGGER.warn("Failed to unmarshall object", e);
287 return Stream.empty();
291 final GraphTraversal<Vertex, Vertex> query = graphInstance.traversal().V();
293 for (Entry<String, Object> filter : queryParams.entrySet()) {
294 if (filter.getKey().equals(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
295 continue; //For performance reasons, the label is the last thing to be added
297 query.has(filter.getKey(), filter.getValue());
301 if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
302 hasLabel(query, queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString()));
305 final Iterator<ChampObject> objIter = new Iterator<ChampObject> () {
307 private ChampObject next;
311 public boolean hasNext() {
312 while (query.hasNext()) {
314 next = getChampformer().unmarshallObject(query.next());
316 } catch (ChampUnmarshallingException e) {
317 LOGGER.warn("Failed to unmarshall tinkerpop vertex during query, returning partial results", e);
321 // If we auto-created the transaction, then commit it now, otherwise it is up to the
322 // caller to decide when and if to do the commit.
323 if(!transaction.isPresent()) {
325 tx.commit(); //Danger ahead if this iterator is not completely consumed
326 //then the transaction cache will hold stale values
327 } catch (ChampTransactionException e) {
328 LOGGER.warn("Failed transaction commit due to: " + e.getMessage());
338 public ChampObject next() {
340 throw new NoSuchElementException();
347 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(objIter,
348 Spliterator.ORDERED | Spliterator.NONNULL),
353 public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException, ChampTransactionException {
354 return retrieveObject(key, Optional.empty());
358 public Optional<ChampObject> retrieveObject(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException {
361 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
364 // If we were not provided a transaction object then automatically open a transaction
366 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
368 // Use the graph instance associated with our transaction.
369 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
371 final Iterator<Vertex> vertices = graphInstance.vertices(key);
372 final Optional<ChampObject> optionalObject;
374 if (!vertices.hasNext()) {
375 optionalObject = Optional.empty();
378 optionalObject = Optional.of(getChampformer().unmarshallObject(vertices.next()));
381 // If we auto-created the transaction, then commit it now, otherwise it is up to the
382 // caller to decide when and if to do the commit.
383 if(!transaction.isPresent()) {
387 return optionalObject;
391 public Stream<ChampRelationship> retrieveRelationships(ChampObject source) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
392 return retrieveRelationships(source, Optional.empty());
396 public Stream<ChampRelationship> retrieveRelationships(ChampObject source, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
399 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
402 // If we were not provided a transaction object then automatically open a transaction
404 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
406 // Use the graph instance associated with our transaction.
407 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
409 final Vertex sourceVertex;
412 sourceVertex = graphInstance.vertices(source.getKey().get()).next();
414 } catch (NoSuchElementException e) {
416 // If we auto-created the transaction, then try to roll it back now, otherwise it is
417 // up to the caller to decide when and if to do so.
418 if(!transaction.isPresent()) {
422 throw new ChampObjectNotExistsException();
425 final Iterator<Edge> edges = sourceVertex.edges(Direction.BOTH);
426 final Iterator<ChampRelationship> relIter = new Iterator<ChampRelationship> () {
428 private ChampRelationship next;
431 public boolean hasNext() {
432 while (edges.hasNext()) {
434 next = getChampformer().unmarshallRelationship(edges.next());
436 } catch (ChampUnmarshallingException e) {
437 LOGGER.warn("Failed to unmarshall tinkerpop edge during query, returning partial results", e);
441 // If we auto-created the transaction, then commit it now, otherwise it is up to the
442 // caller to decide when and if to do the commit.
443 if(!transaction.isPresent()) {
445 tx.commit(); //Danger ahead if this iterator is not completely
446 //consumed, then the transaction cache will be stale
448 } catch (ChampTransactionException e) {
449 LOGGER.warn("Failed transaction commit due to: " + e.getMessage());
458 public ChampRelationship next() {
460 throw new NoSuchElementException();
467 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
468 relIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
473 public ChampObject doStoreObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
475 ChampTransaction tx = null;
479 // If we were not provided a transaction object then automatically open a transaction
481 tx = getOrCreateTransactionInstance(transaction);
483 // Now, store the object that we were supplied.
484 final Vertex vertex = writeVertex(object, tx);
486 // Only auto-commit this operation if we were NOT provided a transaction context,
487 // otherwise it is the caller's responsibility to commit the transaction when it
488 // is appropriate to do so.
489 if(!transaction.isPresent()) {
493 // Marshal the resulting vertex into a ChampObject and return it to the caller.
494 return ChampObject.create()
496 .withKey(vertex.id())
499 } catch (ChampObjectNotExistsException e) {
501 // Something went wrong. If we auto-created the transaction, then try to roll it back
502 // now. If we were supplied a transaction context then it is the caller's responsibility
503 // to decide whether or not to roll it back.
504 if(!transaction.isPresent()) {
508 // Rethrow the exception.
514 public ChampObject doReplaceObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
516 ChampTransaction tx = null;
520 // If we were not provided a transaction object then automatically open a transaction
522 tx = getOrCreateTransactionInstance(transaction);
524 final Vertex vertex = replaceVertex(object, tx);
526 // Only auto-commit this operation if we were NOT provided a transaction context,
527 // otherwise it is the caller's responsibility to commit the transaction when it
528 // is appropriate to do so.
529 if(!transaction.isPresent()) {
533 // Marshal the resulting vertex into a ChampObject and return it to the caller.
534 return ChampObject.create()
536 .withKey(vertex.id())
539 } catch (ChampObjectNotExistsException e) {
541 // Something went wrong. If we auto-created the transaction, then try to roll it back
542 // now. If we were supplied a transaction context then it is the caller's responsibility
543 // to decide whether or not to roll it back.
544 if(!transaction.isPresent()) {
548 // Rethrow the exception.
554 public void executeDeleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException, ChampTransactionException {
557 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
560 // If we were not provided a transaction object then automatically open a transaction
562 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
564 // Use the graph instance associated with our transaction.
565 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
567 final Iterator<Vertex> vertex = graphInstance.vertices(key);
569 if (!vertex.hasNext()) {
571 // If we auto-created the transaction, then roll it back now, otherwise it
572 // is up to the caller to make that determination.
573 if(!transaction.isPresent()) {
577 throw new ChampObjectNotExistsException();
580 // Remove the vertex.
581 vertex.next().remove();
583 // If we auto-created the transaction, then commit it now, otherwise it
584 // is up to the caller to decide if and when to commit.
585 if(!transaction.isPresent()) {
591 public ChampRelationship doStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
592 throws ChampUnmarshallingException,
593 ChampObjectNotExistsException,
594 ChampRelationshipNotExistsException,
595 ChampMarshallingException,
596 ChampTransactionException {
598 // If we were not provided a transaction object then automatically open a transaction
600 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
604 // Store the edge in the graph.
605 final Edge edge = writeEdge(relationship, tx);
607 // Unmarshal the stored edge into a ChampRelationship object
608 ChampRelationship storedRelationship = getChampformer().unmarshallRelationship(edge);
610 // If we auto-created the transaction, then commit it now, otherwise it
611 // is up to the caller to decide if and when to commit.
612 if(!transaction.isPresent()) {
616 // Finally, return the result to the caller.
617 return storedRelationship;
619 } catch (ChampObjectNotExistsException |
620 ChampRelationshipNotExistsException |
621 ChampUnmarshallingException |
622 ChampMarshallingException e) {
624 // If we auto-create the transaction, then try to roll it back, otherwise
625 // it is up to the caller to decide when and if to do so.
626 if(!transaction.isPresent()) {
635 public ChampRelationship doReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
636 throws ChampUnmarshallingException,
637 ChampRelationshipNotExistsException,
638 ChampMarshallingException,
639 ChampTransactionException {
641 // If we were not provided a transaction object then automatically open a transaction
643 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
646 final Edge edge = replaceEdge(relationship, tx);
648 ChampRelationship unmarshalledRelationship = getChampformer().unmarshallRelationship(edge);
650 // If we auto-created the transaction, then commit it now, otherwise it
651 // is up to the caller to decide if and when to commit.
652 if(!transaction.isPresent()) {
656 return unmarshalledRelationship;
658 } catch ( ChampRelationshipNotExistsException | ChampUnmarshallingException | ChampMarshallingException e) {
660 // it is up to the caller to decide when and if to do so.
661 if(!transaction.isPresent()) {
670 public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) throws ChampTransactionException {
671 return queryRelationships(queryParams, Optional.empty());
675 public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
678 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
681 // If we were not provided a transaction object then automatically open a transaction
683 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
685 // Use the graph instance associated with our transaction.
686 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
688 // If they provided the relationship key, do this the quick way rather than creating a traversal
689 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString())) {
691 final Optional<ChampRelationship> relationship = retrieveRelationship(queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString()),
694 if (relationship.isPresent()) {
695 return Stream.of(relationship.get());
698 return Stream.empty();
700 } catch (ChampUnmarshallingException e) {
702 LOGGER.warn("Failed to unmarshall relationship", e);
703 return Stream.empty();
707 final GraphTraversal<Edge, Edge> query = graphInstance.traversal().E();
709 for (Entry<String, Object> filter : queryParams.entrySet()) {
710 if (filter.getKey().equals(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
711 continue; //Add the label last for performance reasons
713 query.has(filter.getKey(), filter.getValue());
717 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
718 hasLabel(query, queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString()));
721 final Iterator<ChampRelationship> objIter = new Iterator<ChampRelationship> () {
723 private ChampRelationship next;
726 public boolean hasNext() {
727 while (query.hasNext()) {
729 next = getChampformer().unmarshallRelationship(query.next());
731 } catch (ChampUnmarshallingException e) {
732 LOGGER.warn("Failed to unmarshall tinkerpop vertex during query, returning partial results", e);
736 // If we auto-created the transaction, then commit it now, otherwise it
737 // is up to the caller to decide if and when to commit.
738 if(!transaction.isPresent()) {
740 tx.commit(); //Danger ahead if this iterator is not completely
741 //consumed, then the transaction cache will be stale
743 } catch (ChampTransactionException e) {
744 LOGGER.warn("Failed transaction commit due to " + e.getMessage());
754 public ChampRelationship next() {
756 throw new NoSuchElementException();
763 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
764 objIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
768 public Optional<ChampRelationship> retrieveRelationship(Object key)
769 throws ChampUnmarshallingException, ChampTransactionException {
770 return retrieveRelationship(key, Optional.empty());
774 public Optional<ChampRelationship> retrieveRelationship(Object key, Optional<ChampTransaction> transaction)
775 throws ChampUnmarshallingException, ChampTransactionException {
778 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
781 // If we were not provided a transaction object then automatically open a transaction
783 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
785 // Use the graph instance associated with our transaction.
786 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
788 final Iterator<Edge> edge = graphInstance.edges(key);
789 final Optional<ChampRelationship> optionalRelationship;
791 if (!edge.hasNext()) {
792 optionalRelationship = Optional.empty();
794 optionalRelationship = Optional.of(getChampformer().unmarshallRelationship(edge.next()));
797 // If we auto-created the transaction, then commit it now, otherwise it
798 // is up to the caller to decide if and when to commit.
799 if(!transaction.isPresent()) {
803 return optionalRelationship;
807 public void executeDeleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampTransactionException {
810 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
813 if (!relationship.getKey().isPresent()) {
814 throw new IllegalArgumentException("Key must be provided when deleting a relationship");
817 // If we were not provided a transaction object then automatically open a transaction
819 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
821 // Use the graph instance associated with our transaction.
822 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
824 final Iterator<Edge> edge = graphInstance.edges(relationship.getKey().get());
826 if (!edge.hasNext()) {
828 // If we auto-created the transaction, then try to roll it back now, otherwise it
829 // is up to the caller to decide if and when to do so.
830 if(!transaction.isPresent()) {
834 throw new ChampRelationshipNotExistsException();
837 edge.next().remove();
839 // If we auto-created the transaction, then commit it now, otherwise it
840 // is up to the caller to decide if and when to commit.
841 if(!transaction.isPresent()) {
848 public ChampPartition doStorePartition(ChampPartition submittedPartition, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampTransactionException {
851 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
854 // If we were not provided a transaction object then automatically open a transaction
856 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
859 final HashMap<ChampObject, ChampObject> objectsWithKeys = new HashMap<ChampObject, ChampObject> ();
860 final CreateChampPartitionable storedPartition = ChampPartition.create();
862 for (ChampObject champObject : submittedPartition.getChampObjects()) {
863 final Vertex vertex = writeVertex(champObject, tx);
864 objectsWithKeys.put(champObject, ChampObject.create()
866 .withKey(vertex.id())
870 for (ChampRelationship champRelationship : submittedPartition.getChampRelationships()) {
872 if (!objectsWithKeys.containsKey(champRelationship.getSource())) {
873 final Vertex vertex = writeVertex(champRelationship.getSource(), tx);
875 objectsWithKeys.put(champRelationship.getSource(), ChampObject.create()
876 .from(champRelationship.getSource())
877 .withKey(vertex.id())
881 if (!objectsWithKeys.containsKey(champRelationship.getTarget())) {
882 final Vertex vertex = writeVertex(champRelationship.getTarget(), tx);
884 objectsWithKeys.put(champRelationship.getTarget(), ChampObject.create()
885 .from(champRelationship.getTarget())
886 .withKey(vertex.id())
890 final ChampRelationship.Builder relWithKeysBuilder = new ChampRelationship.Builder(objectsWithKeys.get(champRelationship.getSource()),
891 objectsWithKeys.get(champRelationship.getTarget()),
892 champRelationship.getType());
894 if (champRelationship.getKey().isPresent()) {
895 relWithKeysBuilder.key(champRelationship.getKey().get());
898 relWithKeysBuilder.properties(champRelationship.getProperties());
900 final Edge edge = writeEdge(relWithKeysBuilder.build(), tx);
902 storedPartition.withRelationship(ChampRelationship.create()
903 .from(champRelationship)
908 for (ChampObject object : objectsWithKeys.values()) {
909 storedPartition.withObject(object);
912 // If we auto-created the transaction, then commit it now, otherwise it
913 // is up to the caller to decide if and when to commit.
914 if(!transaction.isPresent()) {
918 return storedPartition.build();
920 } catch (ChampObjectNotExistsException | ChampMarshallingException e) {
922 // If we auto-created the transaction, then try to roll it back now, otherwise it
923 // is up to the caller to decide if and when to do so.
924 if(!transaction.isPresent()) {
933 public void executeDeletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) throws ChampTransactionException {
936 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
939 // If we were not provided a transaction object then automatically open a transaction
941 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
943 // Use the graph instance associated with our transaction.
944 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
946 for (ChampObject champObject : graph.getChampObjects()) {
948 final Object vertexId = champObject.getKey().get();
949 final Iterator<Vertex> vertex = graphInstance.vertices(vertexId);
951 if (vertex.hasNext()) {
952 vertex.next().remove();
954 } catch (NoSuchElementException e) {
956 // If we auto-created the transaction, then try to roll it back now, otherwise it
957 // is up to the caller to decide if and when to do so.
958 if(!transaction.isPresent()) {
962 throw new IllegalArgumentException("Must pass a key to delete an object");
966 for (ChampRelationship champRelationship : graph.getChampRelationships()) {
968 final Iterator<Edge> edge = graphInstance.edges(champRelationship.getKey().get());
970 if (edge.hasNext()) {
971 edge.next().remove();
973 } catch (NoSuchElementException e) {
975 // If we auto-created the transaction, then try to roll it back now, otherwise it
976 // is up to the caller to decide if and when to do so.
977 if(!transaction.isPresent()) {
981 throw new IllegalArgumentException("Must pass a key to delete a relationship");
985 // If we auto-created the transaction, then commit it now, otherwise it
986 // is up to the caller to decide if and when to commit.
987 if(!transaction.isPresent()) {
993 public void shutdown() {
995 if (isShutdown.compareAndSet(false, true)) {
999 } catch (Throwable t) {
1000 LOGGER.error("Exception while shutting down graph", t);
1003 throw new IllegalStateException("Cannot call shutdown() after shutdown() was already initiated");
1008 public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException {
1009 if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated");
1011 if (getGraph().features().graph().variables().supportsVariables()) {
1013 getGraph().variables().set("schema", getObjectMapper().writeValueAsBytes(schema));
1014 } catch (JsonProcessingException e) {
1015 throw new RuntimeException(e);
1018 super.storeSchema(schema);
1023 public ChampSchema retrieveSchema() {
1024 if (isShutdown()) throw new IllegalStateException("Cannot call retrieveSchema() after shutdown has been initiated");
1026 if (getGraph().features().graph().variables().supportsVariables()) {
1027 final Optional<byte[]> schema = getGraph().variables().get("schema");
1029 if (schema.isPresent()) {
1031 return getObjectMapper().readValue(schema.get(), ChampSchema.class);
1032 } catch (IOException e) {
1033 throw new RuntimeException(e);
1038 return super.retrieveSchema();
1042 public void deleteSchema() {
1043 if (isShutdown()) throw new IllegalStateException("Cannot call deleteSchema() after shutdown has been initiated");
1045 if (getGraph().features().graph().variables().supportsVariables()) {
1046 getGraph().variables().remove("schema");
1048 super.deleteSchema();
1052 public ChampTransaction getOrCreateTransactionInstance(Optional<ChampTransaction> transaction) {
1054 ChampTransaction tx = null;
1056 // If we were not provided a transaction object then automatically open a transaction
1058 if(!transaction.isPresent()) {
1060 tx = new TinkerpopTransaction(getGraph());
1063 tx = transaction.get();