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.concurrent.atomic.AtomicBoolean;
35 import java.util.stream.Stream;
36 import java.util.stream.StreamSupport;
38 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
39 import org.apache.tinkerpop.gremlin.structure.Direction;
40 import org.apache.tinkerpop.gremlin.structure.Edge;
41 import org.apache.tinkerpop.gremlin.structure.Graph;
42 import org.apache.tinkerpop.gremlin.structure.Property;
43 import org.apache.tinkerpop.gremlin.structure.Vertex;
44 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
45 import org.onap.aai.champcore.ChampCoreMsgs;
46 import org.onap.aai.champcore.ChampTransaction;
47 import org.onap.aai.champcore.exceptions.ChampMarshallingException;
48 import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
49 import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
50 import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
51 import org.onap.aai.champcore.exceptions.ChampTransactionException;
52 import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
53 import org.onap.aai.champcore.model.ChampObject;
54 import org.onap.aai.champcore.model.ChampPartition;
55 import org.onap.aai.champcore.model.ChampRelationship;
56 import org.onap.aai.champcore.model.ChampSchema;
57 import org.onap.aai.champcore.model.fluent.partition.CreateChampPartitionable;
58 import org.onap.aai.champcore.transform.TinkerpopChampformer;
59 import org.onap.aai.cl.api.Logger;
60 import org.onap.aai.cl.eelf.LoggerFactory;
62 import com.fasterxml.jackson.core.JsonProcessingException;
63 import com.fasterxml.jackson.databind.ObjectMapper;
65 public abstract class AbstractTinkerpopChampGraph extends AbstractValidatingChampGraph {
67 private static final Logger LOGGER = LoggerFactory.getInstance().getLogger(AbstractTinkerpopChampGraph.class);
68 private static final TinkerpopChampformer TINKERPOP_CHAMPFORMER = new TinkerpopChampformer();
69 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
71 private volatile AtomicBoolean isShutdown;
73 protected AbstractTinkerpopChampGraph(Map<String, Object> properties) {
76 isShutdown = new AtomicBoolean(false);
77 Runtime.getRuntime().addShutdownHook(shutdownHook);
80 private static final TinkerpopChampformer getChampformer() {
81 return TINKERPOP_CHAMPFORMER;
84 private static final ObjectMapper getObjectMapper() {
88 public abstract GraphTraversal<?, ?> hasLabel(GraphTraversal<?, ?> query, Object type);
90 public ChampTransaction openTransaction() {
92 return new TinkerpopTransaction(getGraph());
95 private Vertex writeVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
98 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
100 if (object.getKey().isPresent()) {
101 final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
103 if (vertexIter.hasNext()) {
104 vertex = vertexIter.next();
105 } else throw new ChampObjectNotExistsException();
107 vertex = graphInstance.addVertex(object.getType());
110 for (Entry<String, Object> property : object.getProperties().entrySet()) {
112 if (property.getValue() instanceof List) {
113 for (Object subPropertyValue : (List<?>) property.getValue()) {
114 vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
116 } else if (property.getValue() instanceof Set) {
117 for (Object subPropertyValue : (Set<?>) property.getValue()) {
118 vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
121 vertex.property(property.getKey(), property.getValue());
128 private Vertex replaceVertex(ChampObject object, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampMarshallingException {
131 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
133 if (object.getKey().isPresent()) {
134 final Iterator<Vertex> vertexIter = graphInstance.vertices(object.getKey().get());
136 if (vertexIter.hasNext()) {
137 vertex = vertexIter.next();
138 } else throw new ChampObjectNotExistsException();
140 throw new ChampObjectNotExistsException();
143 //clear all the existing properties
144 Iterator<VertexProperty<Object>> it = vertex.properties();
145 while (it.hasNext()) {
149 for (Entry<String, Object> property : object.getProperties().entrySet()) {
151 if (property.getValue() instanceof List) {
152 for (Object subPropertyValue : (List<?>) property.getValue()) {
153 vertex.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
155 } else if (property.getValue() instanceof Set) {
156 for (Object subPropertyValue : (Set<?>) property.getValue()) {
157 vertex.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
160 vertex.property(property.getKey(), property.getValue());
167 private Edge writeEdge(ChampRelationship relationship, ChampTransaction transaction) throws ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException {
169 final Vertex source = writeVertex(relationship.getSource(), transaction);
170 final Vertex target = writeVertex(relationship.getTarget(), transaction);
173 Graph graphInstance = ((TinkerpopTransaction)transaction).getGraphInstance();
175 if (relationship.getKey().isPresent()) {
176 final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
178 if (edgeIter.hasNext()) {
179 edge = edgeIter.next();
180 } else throw new ChampRelationshipNotExistsException();
182 edge = source.addEdge(relationship.getType(), target);
185 for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
186 edge.property(property.getKey(), property.getValue());
192 private Edge replaceEdge(ChampRelationship relationship, ChampTransaction tx) throws ChampRelationshipNotExistsException, ChampMarshallingException {
194 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
196 if(!relationship.getSource().getKey().isPresent() || !relationship.getTarget().getKey().isPresent()){
197 throw new IllegalArgumentException("Invalid source/target");
200 if (relationship.getKey().isPresent()) {
201 final Iterator<Edge> edgeIter = graphInstance.edges(relationship.getKey().get());
204 if (edgeIter.hasNext()) {
205 edge = edgeIter.next();
206 //validate if the source/target are the same as before. Throw error if not the same
207 if (!edge.outVertex().id().equals(relationship.getSource().getKey().get())
208 || !edge.inVertex().id().equals(relationship.getTarget().getKey().get())) {
209 throw new IllegalArgumentException("source/target can't be updated");
212 } else throw new ChampRelationshipNotExistsException();
214 throw new ChampRelationshipNotExistsException();
217 // clear all the existing properties
218 Iterator<Property<Object>> it = edge.properties();
219 while (it.hasNext()) {
223 for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
224 edge.property(property.getKey(), property.getValue());
231 protected abstract Graph getGraph();
235 private Thread shutdownHook = new Thread() {
240 } catch (IllegalStateException e) {
241 //Suppress, because shutdown() has already been called
246 protected boolean isShutdown() {
247 return isShutdown.get();
251 public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) throws ChampTransactionException {
252 return queryObjects(queryParams, Optional.empty());
257 public Stream<ChampObject> queryObjects(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
260 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
263 // If we were not provided a transaction object then automatically open a transaction
265 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
267 // Use the graph instance associated with our transaction.
268 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
270 //If they provided the object key, do this the quick way rather than creating a traversal
271 if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString())) {
274 final Optional<ChampObject> object =
275 retrieveObject(queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString()),
278 if (object.isPresent()) {
279 return Stream.of(object.get());
281 return Stream.empty();
283 } catch (ChampUnmarshallingException e) {
284 LOGGER.warn(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
285 "Failed to unmarshall object. " + e.getMessage());
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(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
317 "Failed to unmarshall tinkerpop vertex during query, returning partial results" + e.getMessage());
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(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
329 "Failed transaction commit due to: " + e.getMessage());
339 public ChampObject next() {
341 throw new NoSuchElementException();
348 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(objIter,
349 Spliterator.ORDERED | Spliterator.NONNULL),
354 public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException, ChampTransactionException {
355 return retrieveObject(key, Optional.empty());
359 public Optional<ChampObject> retrieveObject(Object key, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampTransactionException {
362 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
365 // If we were not provided a transaction object then automatically open a transaction
367 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
369 // Use the graph instance associated with our transaction.
370 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
372 final Iterator<Vertex> vertices = graphInstance.vertices(key);
373 final Optional<ChampObject> optionalObject;
375 if (!vertices.hasNext()) {
376 optionalObject = Optional.empty();
379 optionalObject = Optional.of(getChampformer().unmarshallObject(vertices.next()));
382 // If we auto-created the transaction, then commit it now, otherwise it is up to the
383 // caller to decide when and if to do the commit.
384 if(!transaction.isPresent()) {
388 return optionalObject;
392 public Stream<ChampRelationship> retrieveRelationships(ChampObject source) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
393 return retrieveRelationships(source, Optional.empty());
397 public Stream<ChampRelationship> retrieveRelationships(ChampObject source, Optional<ChampTransaction> transaction) throws ChampUnmarshallingException, ChampObjectNotExistsException, ChampTransactionException {
400 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
403 // If we were not provided a transaction object then automatically open a transaction
405 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
407 // Use the graph instance associated with our transaction.
408 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
410 final Vertex sourceVertex;
413 sourceVertex = graphInstance.vertices(source.getKey().get()).next();
415 } catch (NoSuchElementException e) {
417 // If we auto-created the transaction, then try to roll it back now, otherwise it is
418 // up to the caller to decide when and if to do so.
419 if(!transaction.isPresent()) {
423 throw new ChampObjectNotExistsException();
426 final Iterator<Edge> edges = sourceVertex.edges(Direction.BOTH);
427 final Iterator<ChampRelationship> relIter = new Iterator<ChampRelationship> () {
429 private ChampRelationship next;
432 public boolean hasNext() {
433 while (edges.hasNext()) {
435 next = getChampformer().unmarshallRelationship(edges.next());
437 } catch (ChampUnmarshallingException e) {
438 LOGGER.warn(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
439 "Failed to unmarshall tinkerpop edge during query, returning partial results" + e.getMessage());
443 // If we auto-created the transaction, then commit it now, otherwise it is up to the
444 // caller to decide when and if to do the commit.
445 if(!transaction.isPresent()) {
447 tx.commit(); //Danger ahead if this iterator is not completely
448 //consumed, then the transaction cache will be stale
450 } catch (ChampTransactionException e) {
451 LOGGER.warn(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
452 "Failed transaction commit due to: " + e.getMessage());
461 public ChampRelationship next() {
463 throw new NoSuchElementException();
470 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
471 relIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
476 public ChampObject doStoreObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
478 ChampTransaction tx = null;
482 // If we were not provided a transaction object then automatically open a transaction
484 tx = getOrCreateTransactionInstance(transaction);
486 // Now, store the object that we were supplied.
487 final Vertex vertex = writeVertex(object, tx);
489 // Only auto-commit this operation if we were NOT provided a transaction context,
490 // otherwise it is the caller's responsibility to commit the transaction when it
491 // is appropriate to do so.
492 if(!transaction.isPresent()) {
496 // Marshal the resulting vertex into a ChampObject and return it to the caller.
497 return ChampObject.create()
499 .withKey(vertex.id())
502 } catch (ChampObjectNotExistsException e) {
504 // Something went wrong. If we auto-created the transaction, then try to roll it back
505 // now. If we were supplied a transaction context then it is the caller's responsibility
506 // to decide whether or not to roll it back.
507 if(!transaction.isPresent()) {
511 // Rethrow the exception.
517 public ChampObject doReplaceObject(ChampObject object, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampTransactionException {
519 ChampTransaction tx = null;
523 // If we were not provided a transaction object then automatically open a transaction
525 tx = getOrCreateTransactionInstance(transaction);
527 final Vertex vertex = replaceVertex(object, tx);
529 // Only auto-commit this operation if we were NOT provided a transaction context,
530 // otherwise it is the caller's responsibility to commit the transaction when it
531 // is appropriate to do so.
532 if(!transaction.isPresent()) {
536 // Marshal the resulting vertex into a ChampObject and return it to the caller.
537 return ChampObject.create()
539 .withKey(vertex.id())
542 } catch (ChampObjectNotExistsException e) {
544 // Something went wrong. If we auto-created the transaction, then try to roll it back
545 // now. If we were supplied a transaction context then it is the caller's responsibility
546 // to decide whether or not to roll it back.
547 if(!transaction.isPresent()) {
551 // Rethrow the exception.
557 public void executeDeleteObject(Object key, Optional<ChampTransaction> transaction) throws ChampObjectNotExistsException, ChampTransactionException {
560 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
563 // If we were not provided a transaction object then automatically open a transaction
565 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
567 // Use the graph instance associated with our transaction.
568 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
570 final Iterator<Vertex> vertex = graphInstance.vertices(key);
572 if (!vertex.hasNext()) {
574 // If we auto-created the transaction, then roll it back now, otherwise it
575 // is up to the caller to make that determination.
576 if(!transaction.isPresent()) {
580 throw new ChampObjectNotExistsException();
583 // Remove the vertex.
584 vertex.next().remove();
586 // If we auto-created the transaction, then commit it now, otherwise it
587 // is up to the caller to decide if and when to commit.
588 if(!transaction.isPresent()) {
594 public ChampRelationship doStoreRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
595 throws ChampUnmarshallingException,
596 ChampObjectNotExistsException,
597 ChampRelationshipNotExistsException,
598 ChampMarshallingException,
599 ChampTransactionException {
601 // If we were not provided a transaction object then automatically open a transaction
603 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
607 // Store the edge in the graph.
608 final Edge edge = writeEdge(relationship, tx);
610 // Unmarshal the stored edge into a ChampRelationship object
611 ChampRelationship storedRelationship = getChampformer().unmarshallRelationship(edge);
613 // If we auto-created the transaction, then commit it now, otherwise it
614 // is up to the caller to decide if and when to commit.
615 if(!transaction.isPresent()) {
619 // Finally, return the result to the caller.
620 return storedRelationship;
622 } catch (ChampObjectNotExistsException |
623 ChampRelationshipNotExistsException |
624 ChampUnmarshallingException |
625 ChampMarshallingException e) {
627 // If we auto-create the transaction, then try to roll it back, otherwise
628 // it is up to the caller to decide when and if to do so.
629 if(!transaction.isPresent()) {
638 public ChampRelationship doReplaceRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction)
639 throws ChampUnmarshallingException,
640 ChampRelationshipNotExistsException,
641 ChampMarshallingException,
642 ChampTransactionException {
644 // If we were not provided a transaction object then automatically open a transaction
646 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
649 final Edge edge = replaceEdge(relationship, tx);
651 ChampRelationship unmarshalledRelationship = getChampformer().unmarshallRelationship(edge);
653 // If we auto-created the transaction, then commit it now, otherwise it
654 // is up to the caller to decide if and when to commit.
655 if(!transaction.isPresent()) {
659 return unmarshalledRelationship;
661 } catch ( ChampRelationshipNotExistsException | ChampUnmarshallingException | ChampMarshallingException e) {
663 // it is up to the caller to decide when and if to do so.
664 if(!transaction.isPresent()) {
673 public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) throws ChampTransactionException {
674 return queryRelationships(queryParams, Optional.empty());
678 public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams, Optional<ChampTransaction> transaction) throws ChampTransactionException {
681 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
684 // If we were not provided a transaction object then automatically open a transaction
686 final ChampTransaction tx = getOrCreateTransactionInstance(transaction);
688 // Use the graph instance associated with our transaction.
689 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
691 // If they provided the relationship key, do this the quick way rather than creating a traversal
692 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString())) {
694 final Optional<ChampRelationship> relationship = retrieveRelationship(queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString()),
697 if (relationship.isPresent()) {
698 return Stream.of(relationship.get());
701 return Stream.empty();
703 } catch (ChampUnmarshallingException e) {
705 LOGGER.warn(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
706 "Failed to unmarshall relationship" + e.getMessage());
707 return Stream.empty();
711 final GraphTraversal<Edge, Edge> query = graphInstance.traversal().E();
713 for (Entry<String, Object> filter : queryParams.entrySet()) {
714 if (filter.getKey().equals(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
715 continue; //Add the label last for performance reasons
717 query.has(filter.getKey(), filter.getValue());
721 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
722 hasLabel(query, queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString()));
725 final Iterator<ChampRelationship> objIter = new Iterator<ChampRelationship> () {
727 private ChampRelationship next;
730 public boolean hasNext() {
731 while (query.hasNext()) {
733 next = getChampformer().unmarshallRelationship(query.next());
735 } catch (ChampUnmarshallingException e) {
736 LOGGER.warn(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
737 "Failed to unmarshall tinkerpop vertex during query, returning partial results" + e.getMessage());
741 // If we auto-created the transaction, then commit it now, otherwise it
742 // is up to the caller to decide if and when to commit.
743 if(!transaction.isPresent()) {
745 tx.commit(); //Danger ahead if this iterator is not completely
746 //consumed, then the transaction cache will be stale
748 } catch (ChampTransactionException e) {
749 LOGGER.warn(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_WARN,
750 "Failed transaction commit due to " + e.getMessage());
760 public ChampRelationship next() {
762 throw new NoSuchElementException();
769 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
770 objIter, Spliterator.ORDERED | Spliterator.NONNULL), false);
774 public Optional<ChampRelationship> retrieveRelationship(Object key)
775 throws ChampUnmarshallingException, ChampTransactionException {
776 return retrieveRelationship(key, Optional.empty());
780 public Optional<ChampRelationship> retrieveRelationship(Object key, Optional<ChampTransaction> transaction)
781 throws ChampUnmarshallingException, ChampTransactionException {
784 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
787 // If we were not provided a transaction object then automatically open a transaction
789 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
791 // Use the graph instance associated with our transaction.
792 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
794 final Iterator<Edge> edge = graphInstance.edges(key);
795 final Optional<ChampRelationship> optionalRelationship;
797 if (!edge.hasNext()) {
798 optionalRelationship = Optional.empty();
800 optionalRelationship = Optional.of(getChampformer().unmarshallRelationship(edge.next()));
803 // If we auto-created the transaction, then commit it now, otherwise it
804 // is up to the caller to decide if and when to commit.
805 if(!transaction.isPresent()) {
809 return optionalRelationship;
813 public void executeDeleteRelationship(ChampRelationship relationship, Optional<ChampTransaction> transaction) throws ChampRelationshipNotExistsException, ChampTransactionException {
816 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
819 if (!relationship.getKey().isPresent()) {
820 throw new IllegalArgumentException("Key must be provided when deleting a relationship");
823 // If we were not provided a transaction object then automatically open a transaction
825 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
827 // Use the graph instance associated with our transaction.
828 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
830 final Iterator<Edge> edge = graphInstance.edges(relationship.getKey().get());
832 if (!edge.hasNext()) {
834 // If we auto-created the transaction, then try to roll it back now, otherwise it
835 // is up to the caller to decide if and when to do so.
836 if(!transaction.isPresent()) {
840 throw new ChampRelationshipNotExistsException();
843 edge.next().remove();
845 // If we auto-created the transaction, then commit it now, otherwise it
846 // is up to the caller to decide if and when to commit.
847 if(!transaction.isPresent()) {
854 public ChampPartition doStorePartition(ChampPartition submittedPartition, Optional<ChampTransaction> transaction) throws ChampMarshallingException, ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampTransactionException {
857 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
860 // If we were not provided a transaction object then automatically open a transaction
862 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
865 final HashMap<ChampObject, ChampObject> objectsWithKeys = new HashMap<ChampObject, ChampObject> ();
866 final CreateChampPartitionable storedPartition = ChampPartition.create();
868 for (ChampObject champObject : submittedPartition.getChampObjects()) {
869 final Vertex vertex = writeVertex(champObject, tx);
870 objectsWithKeys.put(champObject, ChampObject.create()
872 .withKey(vertex.id())
876 for (ChampRelationship champRelationship : submittedPartition.getChampRelationships()) {
878 if (!objectsWithKeys.containsKey(champRelationship.getSource())) {
879 final Vertex vertex = writeVertex(champRelationship.getSource(), tx);
881 objectsWithKeys.put(champRelationship.getSource(), ChampObject.create()
882 .from(champRelationship.getSource())
883 .withKey(vertex.id())
887 if (!objectsWithKeys.containsKey(champRelationship.getTarget())) {
888 final Vertex vertex = writeVertex(champRelationship.getTarget(), tx);
890 objectsWithKeys.put(champRelationship.getTarget(), ChampObject.create()
891 .from(champRelationship.getTarget())
892 .withKey(vertex.id())
896 final ChampRelationship.Builder relWithKeysBuilder = new ChampRelationship.Builder(objectsWithKeys.get(champRelationship.getSource()),
897 objectsWithKeys.get(champRelationship.getTarget()),
898 champRelationship.getType());
900 if (champRelationship.getKey().isPresent()) {
901 relWithKeysBuilder.key(champRelationship.getKey().get());
904 relWithKeysBuilder.properties(champRelationship.getProperties());
906 final Edge edge = writeEdge(relWithKeysBuilder.build(), tx);
908 storedPartition.withRelationship(ChampRelationship.create()
909 .from(champRelationship)
914 for (ChampObject object : objectsWithKeys.values()) {
915 storedPartition.withObject(object);
918 // If we auto-created the transaction, then commit it now, otherwise it
919 // is up to the caller to decide if and when to commit.
920 if(!transaction.isPresent()) {
924 return storedPartition.build();
926 } catch (ChampObjectNotExistsException | ChampMarshallingException e) {
928 // If we auto-created the transaction, then try to roll it back now, otherwise it
929 // is up to the caller to decide if and when to do so.
930 if(!transaction.isPresent()) {
939 public void executeDeletePartition(ChampPartition graph, Optional<ChampTransaction> transaction) throws ChampTransactionException {
942 throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
945 // If we were not provided a transaction object then automatically open a transaction
947 ChampTransaction tx = getOrCreateTransactionInstance(transaction);
949 // Use the graph instance associated with our transaction.
950 Graph graphInstance = ((TinkerpopTransaction)tx).getGraphInstance();
952 for (ChampObject champObject : graph.getChampObjects()) {
954 final Object vertexId = champObject.getKey().get();
955 final Iterator<Vertex> vertex = graphInstance.vertices(vertexId);
957 if (vertex.hasNext()) {
958 vertex.next().remove();
960 } catch (NoSuchElementException e) {
962 // If we auto-created the transaction, then try to roll it back now, otherwise it
963 // is up to the caller to decide if and when to do so.
964 if(!transaction.isPresent()) {
968 throw new IllegalArgumentException("Must pass a key to delete an object");
972 for (ChampRelationship champRelationship : graph.getChampRelationships()) {
974 final Iterator<Edge> edge = graphInstance.edges(champRelationship.getKey().get());
976 if (edge.hasNext()) {
977 edge.next().remove();
979 } catch (NoSuchElementException e) {
981 // If we auto-created the transaction, then try to roll it back now, otherwise it
982 // is up to the caller to decide if and when to do so.
983 if(!transaction.isPresent()) {
987 throw new IllegalArgumentException("Must pass a key to delete a relationship");
991 // If we auto-created the transaction, then commit it now, otherwise it
992 // is up to the caller to decide if and when to commit.
993 if(!transaction.isPresent()) {
999 public void shutdown() {
1001 if (isShutdown.compareAndSet(false, true)) {
1005 } catch (Throwable t) {
1006 LOGGER.error(ChampCoreMsgs.CHAMPCORE_ABSTRACT_TINKERPOP_CHAMP_GRAPH_ERROR,
1007 "Exception while shutting down graph" + t.getMessage());
1010 throw new IllegalStateException("Cannot call shutdown() after shutdown() was already initiated");
1015 public void storeSchema(ChampSchema schema) throws ChampSchemaViolationException {
1016 if (isShutdown()) throw new IllegalStateException("Cannot call storeSchema() after shutdown has been initiated");
1018 if (getGraph().features().graph().variables().supportsVariables()) {
1020 getGraph().variables().set("schema", getObjectMapper().writeValueAsBytes(schema));
1021 } catch (JsonProcessingException e) {
1022 throw new RuntimeException(e);
1025 super.storeSchema(schema);
1030 public ChampSchema retrieveSchema() {
1031 if (isShutdown()) throw new IllegalStateException("Cannot call retrieveSchema() after shutdown has been initiated");
1033 if (getGraph().features().graph().variables().supportsVariables()) {
1034 final Optional<byte[]> schema = getGraph().variables().get("schema");
1036 if (schema.isPresent()) {
1038 return getObjectMapper().readValue(schema.get(), ChampSchema.class);
1039 } catch (IOException e) {
1040 throw new RuntimeException(e);
1045 return super.retrieveSchema();
1049 public void deleteSchema() {
1050 if (isShutdown()) throw new IllegalStateException("Cannot call deleteSchema() after shutdown has been initiated");
1052 if (getGraph().features().graph().variables().supportsVariables()) {
1053 getGraph().variables().remove("schema");
1055 super.deleteSchema();
1059 public ChampTransaction getOrCreateTransactionInstance(Optional<ChampTransaction> transaction) {
1061 ChampTransaction tx = null;
1063 // If we were not provided a transaction object then automatically open a transaction
1065 if(!transaction.isPresent()) {
1067 tx = new TinkerpopTransaction(getGraph());
1070 tx = transaction.get();