2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 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============================================
21 package org.onap.aai.champcore.graph.impl;
23 import java.io.IOException;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
28 import java.util.Map.Entry;
29 import java.util.NoSuchElementException;
30 import java.util.Optional;
32 import java.util.Spliterator;
33 import java.util.Spliterators;
34 import java.util.Vector;
35 import java.util.concurrent.atomic.AtomicBoolean;
36 import java.util.stream.Stream;
37 import java.util.stream.StreamSupport;
39 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
40 import org.apache.tinkerpop.gremlin.structure.Direction;
41 import org.apache.tinkerpop.gremlin.structure.Edge;
42 import org.apache.tinkerpop.gremlin.structure.Graph;
43 import org.apache.tinkerpop.gremlin.structure.Property;
44 import org.apache.tinkerpop.gremlin.structure.Vertex;
45 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
46 import org.onap.aai.champcore.ChampTransaction;
47 import org.onap.aai.champcore.NoOpTinkerPopTransaction;
48 import org.onap.aai.champcore.exceptions.ChampMarshallingException;
49 import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
50 import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
51 import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
52 import org.onap.aai.champcore.exceptions.ChampTransactionException;
53 import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
54 import org.onap.aai.champcore.model.ChampObject;
55 import org.onap.aai.champcore.model.ChampPartition;
56 import org.onap.aai.champcore.model.ChampRelationship;
57 import org.onap.aai.champcore.model.ChampSchema;
58 import org.onap.aai.champcore.model.fluent.partition.CreateChampPartitionable;
59 import org.onap.aai.champcore.transform.TinkerpopChampformer;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
63 import com.fasterxml.jackson.core.JsonProcessingException;
64 import com.fasterxml.jackson.databind.ObjectMapper;
66 public abstract class AbstractTinkerpopChampGraph extends AbstractValidatingChampGraph {
68 private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTinkerpopChampGraph.class);
69 private static final TinkerpopChampformer TINKERPOP_CHAMPFORMER = new TinkerpopChampformer();
70 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
72 private volatile AtomicBoolean isShutdown;
74 protected AbstractTinkerpopChampGraph(Map<String, Object> properties) {
77 isShutdown = new AtomicBoolean(false);
78 Runtime.getRuntime().addShutdownHook(shutdownHook);
81 private static final TinkerpopChampformer getChampformer() {
82 return TINKERPOP_CHAMPFORMER;
85 private static final ObjectMapper getObjectMapper() {
89 public abstract GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type);
91 public ChampTransaction openTransaction() {
93 return new TinkerpopTransaction(getGraph());
96 private Vertex writeVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
99 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
101 if (object.getKey().isPresent()) {
102 final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
104 if (vertexIter.hasNext()) {
105 vertex = vertexIter.next();
106 } else throw new ChampObjectNotExistsException();
108 vertex = graphInstance.addVertex(object.getType());
111 for (Entry<String, Object> property : object.getProperties().entrySet()) {
113 if (property.getValue() instanceof List) {
114 for (Object subPropertyValue : (List<?>) property.getValue()) {
115 vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
117 } else if (property.getValue() instanceof Set) {
118 for (Object subPropertyValue : (Set<?>) property.getValue()) {
119 vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
122 vertex.property(property.getKey(), property.getValue());
129 private Vertex replaceVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
132 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
134 if (object.getKey().isPresent()) {
135 final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
137 if (vertexIter.hasNext()) {
138 vertex = vertexIter.next();
139 } else throw new ChampObjectNotExistsException();
141 throw new ChampObjectNotExistsException();
144 //clear all the existing properties
145 Iterator<VertexProperty<Object>> it = vertex.properties();
146 while (it.hasNext()) {
150 for (Entry<String, Object> property : object.getProperties().entrySet()) {
152 if (property.getValue() instanceof List) {
153 for (Object subPropertyValue : (List<?>) property.getValue()) {
154 vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
156 } else if (property.getValue() instanceof Set) {
157 for (Object subPropertyValue : (Set<?>) property.getValue()) {
158 vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
161 vertex.property(property.getKey(), property.getValue());
168 private Edge writeEdge(ChampRelationship relationship, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException {
170 final Vertex source = writeVertex(relationship.getSource(), transaction);
171 final Vertex target = writeVertex(relationship.getTarget(), transaction);
174 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
176 if (relationship.getKey().isPresent()) {
177 final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
179 if (edgeIter.hasNext()) {
180 edge = edgeIter.next();
181 } else throw new ChampRelationshipNotExistsException();
183 edge = source.addEdge(relationship.getType(), target);
186 for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
187 edge.property(property.getKey(), property.getValue());
193 private Edge replaceEdge(ChampRelationship relationship, ChampTransaction tx) throws ChampRelationshipNotExistsException, ChampMarshallingException {
195 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
197 if(!relationship.getSource().getKey().isPresent() || !relationship.getTarget().getKey().isPresent()){
198 throw new IllegalArgumentException("Invalid source/target");
201 if (relationship.getKey().isPresent()) {
202 final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
205 if (edgeIter.hasNext()) {
206 edge = edgeIter.next();
207 //validate if the source/target are the same as before. Throw error if not the same
208 if (!edge.outVertex().id().equals(relationship.getSource().getKey().get())
209 || !edge.inVertex().id().equals(relationship.getTarget().getKey().get())) {
210 throw new IllegalArgumentException("source/target can't be updated");
213 } else throw new ChampRelationshipNotExistsException();
215 throw new ChampRelationshipNotExistsException();
218 // clear all the existing properties
219 Iterator<Property<Object>> it = edge.properties();
220 while (it.hasNext()) {
224 for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
225 edge.property(property.getKey(), property.getValue());
232 protected abstract Graph getGraph();
236 private Thread shutdownHook = new Thread() {
241 } catch (IllegalStateException e) {
242 //Suppress, because shutdown() has already been called
247 protected boolean isShutdown() {
248 return isShutdown.get();
252 public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) throws ChampTransactionException {
253 return queryObjects(queryParams, Optional.empty());
258 public Stream<ChampObject> queryObjects(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
261 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
264 // If we were not provided a transaction object then automatically open a transaction
266 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
268 // Use the graph instance associated with our transaction.
269 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
271 //If they provided the object key, do this the quick way rather than creating a traversal
272 if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString())) {
275 final Optional<ChampObject> object =
276 retrieveObject(queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString()),
279 if (object.isPresent()) {
280 return Stream.of(object.get());
282 return Stream.empty();
284 } catch (ChampUnmarshallingException e) {
285 LOGGER.warn("Failed to unmarshall object", e);
286 return Stream.empty();
290 final GraphTraversal<Vertex, Vertex> query = graphInstance.traversal().V();
292 for (Entry<String, Object> filter : queryParams.entrySet()) {
293 if (filter.getKey().equals(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
294 continue; //For performance reasons, the label is the last thing to be added
296 query.has(filter.getKey(), filter.getValue());
300 if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
301 hasLabel(query, queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString()));
304 final Iterator<ChampObject> objIter = new Iterator<ChampObject> () {
306 private ChampObject next;
310 public boolean hasNext() {
311 while (query.hasNext()) {
313 next = getChampformer().unmarshallObject(query.next());
315 } catch (ChampUnmarshallingException e) {
316 LOGGER.warn("Failed to unmarshall tinkerpop vertex during query, returning partial results", e);
320 // If we auto-created the transaction, then commit it now, otherwise it is up to the
321 // caller to decide when and if to do the commit.
322 if(!transaction.isPresent()) {
324 tx.commit(); //Danger ahead if this iterator is not completely consumed
325 //then the transaction cache will hold stale values
326 } catch (ChampTransactionException e) {
327 LOGGER.warn("Failed transaction commit due to: " + e.getMessage());
337 public ChampObject next() {
339 throw new NoSuchElementException();
346 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(objIter,
347 Spliterator.ORDERED | Spliterator.NONNULL),
352 public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException, ChampTransactionException {
353 return retrieveObject(key, Optional.empty());
357 public Optional<ChampObject> retrieveObject(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException {
360 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
363 // If we were not provided a transaction object then automatically open a transaction
365 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
367 // Use the graph instance associated with our transaction.
368 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
370 final Iterator<Vertex> vertices = graphInstance.vertices(key);
371 final Optional<ChampObject> optionalObject;
373 if (!vertices.hasNext()) {
374 optionalObject = Optional.empty();
377 optionalObject = Optional.of(getChampformer().unmarshallObject(vertices.next()));
380 // If we auto-created the transaction, then commit it now, otherwise it is up to the
381 // caller to decide when and if to do the commit.
382 if(!transaction.isPresent()) {
386 return optionalObject;
390 public Stream<ChampRelationship> retrieveRelationships(ChampObject source) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
391 return retrieveRelationships(source, Optional.empty());
395 public Stream<ChampRelationship> retrieveRelationships(ChampObject source, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
398 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
401 // If we were not provided a transaction object then automatically open a transaction
403 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
405 // Use the graph instance associated with our transaction.
406 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
408 final Vertex sourceVertex;
411 sourceVertex = graphInstance.vertices(source.getKey().get()).next();
413 } catch (NoSuchElementException e) {
415 // If we auto-created the transaction, then try to roll it back now, otherwise it is
416 // up to the caller to decide when and if to do so.
417 if(!transaction.isPresent()) {
421 throw new ChampObjectNotExistsException();
424 final Iterator<Edge> edges = sourceVertex.edges(Direction.BOTH);
425 final Iterator<ChampRelationship> relIter = new Iterator<ChampRelationship> () {
427 private ChampRelationship next;
430 public boolean hasNext() {
431 while (edges.hasNext()) {
433 next = getChampformer().unmarshallRelationship(edges.next());
435 } catch (ChampUnmarshallingException e) {
436 LOGGER.warn("Failed to unmarshall tinkerpop edge during query, returning partial results", e);
440 // If we auto-created the transaction, then commit it now, otherwise it is up to the
441 // caller to decide when and if to do the commit.
442 if(!transaction.isPresent()) {
444 tx.commit(); //Danger ahead if this iterator is not completely
445 //consumed, then the transaction cache will be stale
447 } catch (ChampTransactionException e) {
448 LOGGER.warn("Failed transaction commit due to: " + e.getMessage());
457 public ChampRelationship next() {
459 throw new NoSuchElementException();
466 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
467 relIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
472 public ChampObject doStoreObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
474 ChampTransaction tx = null;
478 // If we were not provided a transaction object then automatically open a transaction
480 tx = getOrCreateTransactionInstance(transaction);
482 // Now, store the object that we were supplied.
483 final Vertex vertex = writeVertex(object, tx);
485 // Only auto-commit this operation if we were NOT provided a transaction context,
486 // otherwise it is the caller's responsibility to commit the transaction when it
487 // is appropriate to do so.
488 if(!transaction.isPresent()) {
492 // Marshal the resulting vertex into a ChampObject and return it to the caller.
493 return ChampObject.create()
495 .withKey(vertex.id())
498 } catch (ChampObjectNotExistsException e) {
500 // Something went wrong. If we auto-created the transaction, then try to roll it back
501 // now. If we were supplied a transaction context then it is the caller's responsibility
502 // to decide whether or not to roll it back.
503 if(!transaction.isPresent()) {
507 // Rethrow the exception.
513 public ChampObject doReplaceObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
515 ChampTransaction tx = null;
519 // If we were not provided a transaction object then automatically open a transaction
521 tx = getOrCreateTransactionInstance(transaction);
523 final Vertex vertex = replaceVertex(object, tx);
525 // Only auto-commit this operation if we were NOT provided a transaction context,
526 // otherwise it is the caller's responsibility to commit the transaction when it
527 // is appropriate to do so.
528 if(!transaction.isPresent()) {
532 // Marshal the resulting vertex into a ChampObject and return it to the caller.
533 return ChampObject.create()
535 .withKey(vertex.id())
538 } catch (ChampObjectNotExistsException e) {
540 // Something went wrong. If we auto-created the transaction, then try to roll it back
541 // now. If we were supplied a transaction context then it is the caller's responsibility
542 // to decide whether or not to roll it back.
543 if(!transaction.isPresent()) {
547 // Rethrow the exception.
553 public void executeDeleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException, ChampTransactionException {
556 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
559 // If we were not provided a transaction object then automatically open a transaction
561 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
563 // Use the graph instance associated with our transaction.
564 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
566 final Iterator<Vertex> vertex = graphInstance.vertices(key);
568 if (!vertex.hasNext()) {
570 // If we auto-created the transaction, then roll it back now, otherwise it
571 // is up to the caller to make that determination.
572 if(!transaction.isPresent()) {
576 throw new ChampObjectNotExistsException();
579 // Remove the vertex.
580 vertex.next().remove();
582 // If we auto-created the transaction, then commit it now, otherwise it
583 // is up to the caller to decide if and when to commit.
584 if(!transaction.isPresent()) {
590 public ChampRelationship doStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
591 throws ChampUnmarshallingException,
592 ChampObjectNotExistsException,
593 ChampRelationshipNotExistsException,
594 ChampMarshallingException,
595 ChampTransactionException {
597 // If we were not provided a transaction object then automatically open a transaction
599 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
603 // Store the edge in the graph.
604 final Edge edge = writeEdge(relationship, tx);
606 // Unmarshal the stored edge into a ChampRelationship object
607 ChampRelationship storedRelationship = getChampformer().unmarshallRelationship(edge);
609 // If we auto-created the transaction, then commit it now, otherwise it
610 // is up to the caller to decide if and when to commit.
611 if(!transaction.isPresent()) {
615 // Finally, return the result to the caller.
616 return storedRelationship;
618 } catch (ChampObjectNotExistsException |
619 ChampRelationshipNotExistsException |
620 ChampUnmarshallingException |
621 ChampMarshallingException e) {
623 // If we auto-create the transaction, then try to roll it back, otherwise
624 // it is up to the caller to decide when and if to do so.
625 if(!transaction.isPresent()) {
634 public ChampRelationship doReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
635 throws ChampUnmarshallingException,
636 ChampRelationshipNotExistsException,
637 ChampMarshallingException,
638 ChampTransactionException {
640 // If we were not provided a transaction object then automatically open a transaction
642 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
645 final Edge edge = replaceEdge(relationship, tx);
647 ChampRelationship unmarshalledRelationship = getChampformer().unmarshallRelationship(edge);
649 // If we auto-created the transaction, then commit it now, otherwise it
650 // is up to the caller to decide if and when to commit.
651 if(!transaction.isPresent()) {
655 return unmarshalledRelationship;
657 } catch ( ChampRelationshipNotExistsException | ChampUnmarshallingException | ChampMarshallingException e) {
659 // it is up to the caller to decide when and if to do so.
660 if(!transaction.isPresent()) {
669 public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) throws ChampTransactionException {
670 return queryRelationships(queryParams, Optional.empty());
674 public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
677 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
680 // If we were not provided a transaction object then automatically open a transaction
682 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
684 // Use the graph instance associated with our transaction.
685 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
687 // If they provided the relationship key, do this the quick way rather than creating a traversal
688 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString())) {
690 final Optional<ChampRelationship> relationship = retrieveRelationship(queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString()),
693 if (relationship.isPresent()) {
694 return Stream.of(relationship.get());
697 return Stream.empty();
699 } catch (ChampUnmarshallingException e) {
701 LOGGER.warn("Failed to unmarshall relationship", e);
702 return Stream.empty();
706 final GraphTraversal<Edge, Edge> query = graphInstance.traversal().E();
708 for (Entry<String, Object> filter : queryParams.entrySet()) {
709 if (filter.getKey().equals(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
710 continue; //Add the label last for performance reasons
712 query.has(filter.getKey(), filter.getValue());
716 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
717 hasLabel(query, queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString()));
720 final Iterator<ChampRelationship> objIter = new Iterator<ChampRelationship> () {
722 private ChampRelationship next;
725 public boolean hasNext() {
726 while (query.hasNext()) {
728 next = getChampformer().unmarshallRelationship(query.next());
730 } catch (ChampUnmarshallingException e) {
731 LOGGER.warn("Failed to unmarshall tinkerpop vertex during query, returning partial results", e);
735 // If we auto-created the transaction, then commit it now, otherwise it
736 // is up to the caller to decide if and when to commit.
737 if(!transaction.isPresent()) {
739 tx.commit(); //Danger ahead if this iterator is not completely
740 //consumed, then the transaction cache will be stale
742 } catch (ChampTransactionException e) {
743 LOGGER.warn("Failed transaction commit due to " + e.getMessage());
753 public ChampRelationship next() {
755 throw new NoSuchElementException();
762 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
763 objIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
767 public Optional<ChampRelationship> retrieveRelationship(Object key)
768 throws ChampUnmarshallingException, ChampTransactionException {
769 return retrieveRelationship(key, Optional.empty());
773 public Optional<ChampRelationship> retrieveRelationship(Object key, Optional<ChampTransaction> transaction)
774 throws ChampUnmarshallingException, ChampTransactionException {
777 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
780 // If we were not provided a transaction object then automatically open a transaction
782 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
784 // Use the graph instance associated with our transaction.
785 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
787 final Iterator<Edge> edge = graphInstance.edges(key);
788 final Optional<ChampRelationship> optionalRelationship;
790 if (!edge.hasNext()) {
791 optionalRelationship = Optional.empty();
793 optionalRelationship = Optional.of(getChampformer().unmarshallRelationship(edge.next()));
796 // If we auto-created the transaction, then commit it now, otherwise it
797 // is up to the caller to decide if and when to commit.
798 if(!transaction.isPresent()) {
802 return optionalRelationship;
806 public void executeDeleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampTransactionException {
809 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
812 if (!relationship.getKey().isPresent()) {
813 throw new IllegalArgumentException("Key must be provided when deleting a relationship");
816 // If we were not provided a transaction object then automatically open a transaction
818 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
820 // Use the graph instance associated with our transaction.
821 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
823 final Iterator<Edge> edge = graphInstance.edges(relationship.getKey().get());
825 if (!edge.hasNext()) {
827 // If we auto-created the transaction, then try to roll it back now, otherwise it
828 // is up to the caller to decide if and when to do so.
829 if(!transaction.isPresent()) {
833 throw new ChampRelationshipNotExistsException();
836 edge.next().remove();
838 // If we auto-created the transaction, then commit it now, otherwise it
839 // is up to the caller to decide if and when to commit.
840 if(!transaction.isPresent()) {
847 public ChampPartition doStorePartition(ChampPartition submittedPartition, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampTransactionException {
850 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
853 // If we were not provided a transaction object then automatically open a transaction
855 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
858 final HashMap<ChampObject, ChampObject> objectsWithKeys = new HashMap<ChampObject, ChampObject> ();
859 final CreateChampPartitionable storedPartition = ChampPartition.create();
861 for (ChampObject champObject : submittedPartition.getChampObjects()) {
862 final Vertex vertex = writeVertex(champObject, tx);
863 objectsWithKeys.put(champObject, ChampObject.create()
865 .withKey(vertex.id())
869 for (ChampRelationship champRelationship : submittedPartition.getChampRelationships()) {
871 if (!objectsWithKeys.containsKey(champRelationship.getSource())) {
872 final Vertex vertex = writeVertex(champRelationship.getSource(), tx);
874 objectsWithKeys.put(champRelationship.getSource(), ChampObject.create()
875 .from(champRelationship.getSource())
876 .withKey(vertex.id())
880 if (!objectsWithKeys.containsKey(champRelationship.getTarget())) {
881 final Vertex vertex = writeVertex(champRelationship.getTarget(), tx);
883 objectsWithKeys.put(champRelationship.getTarget(), ChampObject.create()
884 .from(champRelationship.getTarget())
885 .withKey(vertex.id())
889 final ChampRelationship.Builder relWithKeysBuilder = new ChampRelationship.Builder(objectsWithKeys.get(champRelationship.getSource()),
890 objectsWithKeys.get(champRelationship.getTarget()),
891 champRelationship.getType());
893 if (champRelationship.getKey().isPresent()) {
894 relWithKeysBuilder.key(champRelationship.getKey().get());
897 relWithKeysBuilder.properties(champRelationship.getProperties());
899 final Edge edge = writeEdge(relWithKeysBuilder.build(), tx);
901 storedPartition.withRelationship(ChampRelationship.create()
902 .from(champRelationship)
907 for (ChampObject object : objectsWithKeys.values()) {
908 storedPartition.withObject(object);
911 // If we auto-created the transaction, then commit it now, otherwise it
912 // is up to the caller to decide if and when to commit.
913 if(!transaction.isPresent()) {
917 return storedPartition.build();
919 } catch (ChampObjectNotExistsException | ChampMarshallingException e) {
921 // If we auto-created the transaction, then try to roll it back now, otherwise it
922 // is up to the caller to decide if and when to do so.
923 if(!transaction.isPresent()) {
932 public void executeDeletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) throws ChampTransactionException {
935 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
938 // If we were not provided a transaction object then automatically open a transaction
940 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
942 // Use the graph instance associated with our transaction.
943 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
945 for (ChampObject champObject : graph.getChampObjects()) {
947 final Object vertexId = champObject.getKey().get();
948 final Iterator<Vertex> vertex = graphInstance.vertices(vertexId);
950 if (vertex.hasNext()) {
951 vertex.next().remove();
953 } catch (NoSuchElementException e) {
955 // If we auto-created the transaction, then try to roll it back now, otherwise it
956 // is up to the caller to decide if and when to do so.
957 if(!transaction.isPresent()) {
961 throw new IllegalArgumentException("Must pass a key to delete an object");
965 for (ChampRelationship champRelationship : graph.getChampRelationships()) {
967 final Iterator<Edge> edge = graphInstance.edges(champRelationship.getKey().get());
969 if (edge.hasNext()) {
970 edge.next().remove();
972 } catch (NoSuchElementException e) {
974 // If we auto-created the transaction, then try to roll it back now, otherwise it
975 // is up to the caller to decide if and when to do so.
976 if(!transaction.isPresent()) {
980 throw new IllegalArgumentException("Must pass a key to delete a relationship");
984 // If we auto-created the transaction, then commit it now, otherwise it
985 // is up to the caller to decide if and when to commit.
986 if(!transaction.isPresent()) {
992 public void shutdown() {
994 if (isShutdown.compareAndSet(false, true)) {
998 } catch (Throwable t) {
999 LOGGER.error("Exception while shutting down graph", t);
1002 throw new IllegalStateException("Cannot call shutdown() after shutdown() was already initiated");
1007 public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException {
1008 if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated");
1010 if (getGraph().features().graph().variables().supportsVariables()) {
1012 getGraph().variables().set("schema", getObjectMapper().writeValueAsBytes(schema));
1013 } catch (JsonProcessingException e) {
1014 throw new RuntimeException(e);
1017 super.storeSchema(schema);
1022 public ChampSchema retrieveSchema() {
1023 if (isShutdown()) throw new IllegalStateException("Cannot call retrieveSchema() after shutdown has been initiated");
1025 if (getGraph().features().graph().variables().supportsVariables()) {
1026 final Optional<byte[]> schema = getGraph().variables().get("schema");
1028 if (schema.isPresent()) {
1030 return getObjectMapper().readValue(schema.get(), ChampSchema.class);
1031 } catch (IOException e) {
1032 throw new RuntimeException(e);
1037 return super.retrieveSchema();
1041 public void deleteSchema() {
1042 if (isShutdown()) throw new IllegalStateException("Cannot call deleteSchema() after shutdown has been initiated");
1044 if (getGraph().features().graph().variables().supportsVariables()) {
1045 getGraph().variables().remove("schema");
1047 super.deleteSchema();
1051 public ChampTransaction getOrCreateTransactionInstance(Optional<ChampTransaction> transaction) {
1053 ChampTransaction tx = null;
1055 // If we were not provided a transaction object then automatically open a transaction
1057 if(!transaction.isPresent()) {
1059 tx = new TinkerpopTransaction(getGraph());
1062 tx = transaction.get();