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.openecomp.aai.champ.graph.impl;
24 import java.util.HashMap;
25 import java.util.List;
27 import java.util.Map.Entry;
28 import java.util.Optional;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
34 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
35 import org.apache.tinkerpop.gremlin.structure.Edge;
36 import org.apache.tinkerpop.gremlin.structure.Vertex;
37 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
38 import org.openecomp.aai.champ.exceptions.ChampMarshallingException;
39 import org.openecomp.aai.champ.exceptions.ChampObjectNotExistsException;
40 import org.openecomp.aai.champ.exceptions.ChampRelationshipNotExistsException;
41 import org.openecomp.aai.champ.exceptions.ChampUnmarshallingException;
42 import org.openecomp.aai.champ.graph.impl.TitanChampGraphImpl.Builder;
43 import org.openecomp.aai.champ.model.ChampElement;
44 import org.openecomp.aai.champ.model.ChampObject;
45 import org.openecomp.aai.champ.model.ChampPartition;
46 import org.openecomp.aai.champ.model.ChampRelationship;
47 import org.openecomp.aai.champ.model.fluent.partition.CreateChampPartitionable;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 public abstract class AbstractGremlinChampGraph extends AbstractValidatingChampGraph {
53 private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGremlinChampGraph.class);
55 protected abstract GraphTraversalSource startTraversal();
56 protected abstract Stream<ChampElement> runTraversal(GraphTraversal<?, ?> traversal);
58 protected AbstractGremlinChampGraph(Map<String, Object> properties) {
63 public Optional<ChampObject> retrieveObject(Object key) throws ChampUnmarshallingException {
64 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
66 final Stream<ChampElement> elements = runTraversal(startTraversal().V(key).limit(1));
68 if (elements.count() == 0) {
69 return Optional.empty();
72 return Optional.of(elements.findFirst().get().asObject());
75 public void executeDeleteObject(Object key) throws ChampObjectNotExistsException {
76 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
78 final Stream<ChampElement> elements = runTraversal(startTraversal().V(key).limit(1));
80 if (elements.count() == 0) {
81 throw new ChampObjectNotExistsException();
84 runTraversal(startTraversal().V(key).drop());
88 public Stream<ChampObject> queryObjects(Map<String, Object> queryParams) {
89 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
91 //If they provided the object key, do this the quick way rather than creating a traversal
92 if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString())) {
94 final Optional<ChampObject> object = retrieveObject(queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_KEY.toString()));
96 if (object.isPresent()) return Stream.of(object.get());
97 else return Stream.empty();
98 } catch (ChampUnmarshallingException e) {
99 LOGGER.warn("Failed to unmarshall object", e);
100 return Stream.empty();
104 final GraphTraversal<?, Vertex> traversal = startTraversal().V();
106 for (Entry<String, Object> filter : queryParams.entrySet()) {
107 if (filter.getKey().equals(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
108 continue; //For performance reasons, the label is the last thing to be added
110 traversal.has(filter.getKey(), filter.getValue());
114 if (queryParams.containsKey(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString())) {
115 traversal.hasLabel((String) queryParams.get(ChampObject.ReservedPropertyKeys.CHAMP_OBJECT_TYPE.toString()));
119 return runTraversal(traversal).map(element -> {
120 return element.asObject(); //Safe, since we're only operating on vertices
125 public Optional<ChampRelationship> retrieveRelationship(Object key) throws ChampUnmarshallingException {
126 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
128 final Stream<ChampElement> elements = runTraversal(startTraversal().E(key).limit(1));
130 if (elements.count() == 0) return Optional.empty();
132 return Optional.of(elements.findFirst().get().asRelationship());
135 public void executeDeleteRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException {
136 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
137 if (!relationship.getKey().isPresent()) throw new IllegalArgumentException("Key must be provided when deleting a relationship");
139 final Stream<ChampElement> elements = runTraversal(startTraversal().E(relationship.getKey().get()).limit(1));
141 if (elements.count() == 0) {
142 throw new ChampRelationshipNotExistsException();
145 runTraversal(startTraversal().E(relationship.getKey().get()).drop());
149 public Stream<ChampRelationship> retrieveRelationships(ChampObject object)
150 throws ChampUnmarshallingException, ChampObjectNotExistsException {
151 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
153 final Stream<ChampElement> elements = runTraversal(startTraversal().V(object.getKey().get()).limit(1).bothE());
155 return elements.map(element -> {
156 return element.asRelationship(); //Safe, since we're only operating on edges
161 public Stream<ChampRelationship> queryRelationships(Map<String, Object> queryParams) {
162 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
164 //If they provided the relationship key, do this the quick way rather than creating a traversal
165 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString())) {
167 final Optional<ChampRelationship> relationship = retrieveRelationship(queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_KEY.toString()));
169 if (relationship.isPresent()) return Stream.of(relationship.get());
170 else return Stream.empty();
171 } catch (ChampUnmarshallingException e) {
172 LOGGER.warn("Failed to unmarshall relationship", e);
173 return Stream.empty();
177 final GraphTraversal<Edge, Edge> traversal = startTraversal().E();
179 for (Entry<String, Object> filter : queryParams.entrySet()) {
180 if (filter.getKey().equals(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
181 continue; //Add the label last for performance reasons
183 traversal.has(filter.getKey(), filter.getValue());
187 if (queryParams.containsKey(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString())) {
188 traversal.hasLabel((String) queryParams.get(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString()));
191 return runTraversal(traversal).map(element -> {
192 return element.asRelationship(); //Safe, since we are only operating on edges
197 public void executeDeletePartition(ChampPartition graph) {
198 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
200 final Object[] objectIds = graph.getChampObjects()
202 .filter(o -> o.getKey().isPresent())
203 .map(o -> { return o.getKey().get(); })
204 .collect(Collectors.toList())
207 final Object[] relationshipIds = graph.getChampRelationships()
209 .filter(o -> o.getKey().isPresent())
210 .map(o -> { return o.getKey().get(); })
211 .collect(Collectors.toList())
214 runTraversal(startTraversal().V(objectIds).drop());
215 runTraversal(startTraversal().E(relationshipIds).drop());
219 protected ChampObject doStoreObject(ChampObject object)
220 throws ChampMarshallingException, ChampObjectNotExistsException {
221 final GraphTraversal<Vertex, Vertex> traversal;
223 if (object.getKey().isPresent()) {
224 traversal = startTraversal().V(object.getKey().get());
226 traversal = startTraversal().addV(object.getType());
229 for (Entry<String, Object> property : object.getProperties().entrySet()) {
231 if (property.getValue() instanceof List) {
232 for (Object subPropertyValue : (List<?>) property.getValue()) {
233 traversal.property(VertexProperty.Cardinality.list, property.getKey(), subPropertyValue);
235 } else if (property.getValue() instanceof Set) {
236 for (Object subPropertyValue : (Set<?>) property.getValue()) {
237 traversal.property(VertexProperty.Cardinality.set, property.getKey(), subPropertyValue);
240 traversal.property(property.getKey(), property.getValue());
244 return runTraversal(traversal).findFirst().get().asObject(); //TODO check if this return the updated vertices
248 protected ChampObject doReplaceObject(ChampObject object)
249 throws ChampMarshallingException, ChampObjectNotExistsException {
250 //TODO: implement the replace method when required
251 throw new UnsupportedOperationException("Method not implemented");
255 protected ChampRelationship doReplaceRelationship(ChampRelationship relationship) throws ChampRelationshipNotExistsException, ChampMarshallingException {
256 //TODO: implement the replace method when required
257 throw new UnsupportedOperationException("Method not implemented");
261 protected ChampRelationship doStoreRelationship(ChampRelationship relationship) throws ChampObjectNotExistsException, ChampRelationshipNotExistsException, ChampMarshallingException {
263 /* FIXME: Only compatible with Tinkerpop 3.2.3 (Titan uses 3.0.1-incubating).
265 final GraphTraversal<?, Vertex> sourceBuilder;
267 if (relationship.getSource().getKey().isPresent()) {
268 sourceBuilder = startTraversal().V(relationship.getSource().getKey().get()).as("source");
270 sourceBuilder = startTraversal().addV(relationship.getSource().getType());
273 for (Entry<String, Object> sourceProperty : relationship.getSource().getProperties().entrySet()) {
274 sourceBuilder.property(sourceProperty.getKey(), sourceProperty.getValue());
277 final GraphTraversal<?, Vertex> targetBuilder;
279 if (relationship.getTarget().getKey().isPresent()) {
280 targetBuilder = sourceBuilder.V(relationship.getTarget().getKey().get()).as("target");
282 targetBuilder = sourceBuilder.addV(relationship.getTarget().getType());
285 for (Entry<String, Object> targetProperty : relationship.getTarget().getProperties().entrySet()) {
286 targetBuilder.property(targetProperty.getKey(), targetProperty.getValue());
289 final GraphTraversal<?, Edge> edgeBuilder = targetBuilder.addE(relationship.getType()).from("source");
291 for (Entry<String, Object> property : relationship.getProperties().entrySet()) {
292 edgeBuilder.property(property.getKey(), property.getValue());
295 return runTraversal(edgeBuilder).filter(e -> e.isRelationship()).findFirst().get().asRelationship();
298 throw new UnsupportedOperationException("Cannot store relationships because of project setup (Incompatible Tinkerpop version in use)");
302 protected ChampPartition doStorePartition(ChampPartition submittedPartition) throws ChampObjectNotExistsException, ChampMarshallingException, ChampRelationshipNotExistsException {
303 if (isShutdown()) throw new IllegalStateException("Cannot use ChampAPI after calling shutdown()");
306 final HashMap<ChampObject, ChampObject> objectsWithKeys = new HashMap<ChampObject, ChampObject> ();
307 final CreateChampPartitionable storedPartition = ChampPartition.create();
309 for (ChampObject champObject : submittedPartition.getChampObjects()) {
311 final ChampObject objectWithKey = doStoreObject(champObject);
312 objectsWithKeys.put(champObject, objectWithKey);
315 for (ChampRelationship champRelationship : submittedPartition.getChampRelationships()) {
316 if (!objectsWithKeys.containsKey(champRelationship.getSource())) {
317 final ChampObject objectWithKey = doStoreObject(champRelationship.getSource());
319 objectsWithKeys.put(champRelationship.getSource(), objectWithKey);
322 if (!objectsWithKeys.containsKey(champRelationship.getTarget())) {
323 final ChampObject objectWithKey = doStoreObject(champRelationship.getTarget());
325 objectsWithKeys.put(champRelationship.getTarget(), objectWithKey);
328 final ChampRelationship.Builder relWithKeysBuilder = new ChampRelationship.Builder(objectsWithKeys.get(champRelationship.getSource()),
329 objectsWithKeys.get(champRelationship.getTarget()),
330 champRelationship.getType());
332 if (champRelationship.getKey().isPresent()) relWithKeysBuilder.key(champRelationship.getKey().get());
334 relWithKeysBuilder.properties(champRelationship.getProperties());
336 final ChampRelationship relationship = doStoreRelationship(relWithKeysBuilder.build());
338 storedPartition.withRelationship(relationship);
341 for (ChampObject object : objectsWithKeys.values()) {
342 storedPartition.withObject(object);
345 return storedPartition.build();
346 } catch (ChampObjectNotExistsException | ChampMarshallingException e) {