2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
22 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
24 package org.openecomp.crud.dao.champ;
26 import java.util.ArrayList;
27 import java.util.List;
29 import java.util.Optional;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.stream.Collectors;
32 import java.util.stream.Stream;
34 import org.openecomp.aai.champcore.ChampGraph;
35 import org.openecomp.aai.champcore.ChampTransaction;
36 import org.openecomp.aai.champcore.exceptions.ChampMarshallingException;
37 import org.openecomp.aai.champcore.exceptions.ChampObjectNotExistsException;
38 import org.openecomp.aai.champcore.exceptions.ChampRelationshipNotExistsException;
39 import org.openecomp.aai.champcore.exceptions.ChampSchemaViolationException;
40 import org.openecomp.aai.champcore.exceptions.ChampTransactionException;
41 import org.openecomp.aai.champcore.exceptions.ChampUnmarshallingException;
42 import org.openecomp.aai.champcore.model.ChampObject;
43 import org.openecomp.aai.champcore.model.ChampRelationship;
44 import org.openecomp.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep;
45 import org.openecomp.cl.api.Logger;
46 import org.openecomp.cl.eelf.LoggerFactory;
47 import org.openecomp.crud.dao.GraphDao;
48 import org.openecomp.crud.entity.Edge;
49 import org.openecomp.crud.entity.Vertex;
50 import org.openecomp.crud.exception.CrudException;
51 import org.openecomp.crud.logging.CrudServiceMsgs;
54 * This is the integration layer between the CRUD API service and the low level Champ library for graph database
57 public class ChampDao implements GraphDao {
59 public static final String CONFIG_STORAGE_BACKEND = "storage.backend";
60 public static final String CONFIG_STORAGE_BACKEND_DB = "storage.backend.db";
61 public static final String STORAGE_HBASE_DB = "hbase";
62 public static final String STORAGE_CASSANDRA_DB = "cassandra";
63 public static final String CONFIG_STORAGE_HOSTNAMES = "storage.hostnames";
64 public static final String CONFIG_STORAGE_PORT = "storage.port";
65 public static final String CONFIG_HBASE_ZNODE_PARENT = "storage.hbase.ext.zookeeper.znode.parent";
66 public static final String CONFIG_GRAPH_NAME = "graph.name";
67 public static final String GRAPH_UNQ_INSTANCE_ID_SUFFIX = "graph.unique-instance-id-suffix";
69 public static final String CONFIG_EVENT_STREAM_PUBLISHER = "event.stream.publisher";
70 public static final String CONFIG_EVENT_STREAM_NUM_PUBLISHERS = "event.stream.num-publishers";
72 private static Map<String, ChampTransaction> transactions = new ConcurrentHashMap<String, ChampTransaction>();
73 public static final String DEFAULT_GRAPH_NAME = "default_graph";
75 private enum GraphType {
80 * Instance of the API used for interacting with the Champ library.
82 private ChampGraph champApi = null;
84 private Logger logger = LoggerFactory.getInstance().getLogger(ChampDao.class.getName());
87 * Creates a new instance of the ChampDao.
90 * - Concrete implementation of the graph dao layer
92 public ChampDao(ChampGraph champGraph) {
93 this.champApi = champGraph;
97 public Vertex getVertex(String id) throws CrudException {
101 if (logger.isDebugEnabled()) {
102 logger.debug("getVertex with id: " + id);
105 long idAsLong = Long.parseLong(id);
107 Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
109 String nodeType = org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName();
110 if (retrievedVertex.isPresent() && retrievedVertex.get().getProperties().get(nodeType) != null) {
111 return vertexFromChampObject(retrievedVertex.get(), retrievedVertex.get().getProperties().get(nodeType).toString());
114 // We didn't find a vertex with the supplied id, so just throw an
116 throw new CrudException("No vertex with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
119 } catch (ChampUnmarshallingException | ChampTransactionException e) {
121 // Something went wrong - throw an exception.
122 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
127 public Vertex getVertex(String id, String type) throws CrudException {
131 if (logger.isDebugEnabled()) {
132 logger.debug("getVertex with id: " + id);
135 long idAsLong = Long.parseLong(id);
137 // Request the vertex from the graph db.
138 Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
141 if (retrievedVertex.isPresent()
142 && retrievedVertex.get().getProperties().get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) != null
143 && retrievedVertex.get().getProperties().get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()
144 .equalsIgnoreCase(type)) {
146 // Yup, convert it to a Vector object and return it.
147 return vertexFromChampObject(retrievedVertex.get(), type);
151 // We didn't find a vertex with the supplied id, so just throw an
153 throw new CrudException("No vertex with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
156 } catch (ChampUnmarshallingException | ChampTransactionException e) {
158 // Something went wrong - throw an exception.
159 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
164 public List<Edge> getVertexEdges(String id) throws CrudException {
166 if (logger.isDebugEnabled()) {
167 logger.debug("get Edges incident to vertex with id: " + id + " from graph");
171 long idAsLong = Long.parseLong(id); // GDF - what to do about id???
173 // Request the vertex from the graph db.
174 Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
177 if (retrievedVertex.isPresent()) {
179 // Query the Champ library for the edges which are incident to the specified
181 Stream<ChampRelationship> relationships = champApi.retrieveRelationships(retrievedVertex.get());
183 // Build an edge list from the result stream.
184 List<Edge> edges = new ArrayList<Edge>();
185 relationships.forEach(r -> edges.add(edgeFromChampRelationship(r)));
191 // We couldn't find the specified vertex, so throw an exception.
192 throw new CrudException("No vertex with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
195 } catch (ChampUnmarshallingException e) {
197 // Something went wrong, so throw an exception.
198 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
200 } catch (ChampObjectNotExistsException e) {
202 // We couldn't find the specified vertex, so throw an exception.
203 throw new CrudException("No vertex with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
204 } catch (ChampTransactionException e) {
205 throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
210 public Vertex addVertex(String type, Map<String, Object> properties) throws CrudException {
212 if (logger.isDebugEnabled()) {
213 logger.debug("Add/update vertex: {label: " + type + " properties:" + propertiesMapToString(properties));
216 // Add the aai_node_type so that AAI can read the data created by gizmo
217 properties.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
219 // Create an object to represent our vertex in the format expected by the Champ library.
220 ChampObject objectToCreate = buildChampObject(type, properties);
224 // Ask the Champ library to store our vertex, placing the returned object into a
225 // list so that we can easily put that into our result object.
226 return vertexFromChampObject(champApi.storeObject(objectToCreate), type);
228 } catch (ChampMarshallingException | ChampSchemaViolationException | ChampObjectNotExistsException | ChampTransactionException e) {
230 // Something went wrong - throw an exception.
231 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
236 public Vertex updateVertex(String id, String type, Map<String, Object> properties) throws CrudException {
238 if (logger.isDebugEnabled()) {
239 logger.debug("Update vertex with id: " + id + " with properties: " + propertiesMapToString(properties));
241 // Add the aai_node_type so that AAI can read the data created by gizmo
242 properties.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
245 // Now, build the updated version of the Champ Object...
246 ChampObject updateObject = buildChampObject(id, type, properties);
247 // ...and send it to the Champ library.
248 return vertexFromChampObject(champApi.replaceObject(updateObject), type);
250 } catch (ChampObjectNotExistsException e) {
251 throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
252 } catch (NumberFormatException | ChampMarshallingException | ChampSchemaViolationException e) {
253 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
254 } catch (ChampTransactionException e) {
255 throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
261 public List<Vertex> getVertices(String type, Map<String, Object> filter) throws CrudException {
263 if (logger.isDebugEnabled()) {
264 logger.debug("Retrieve vertices with type label: " + type + " which map query parameters: " + propertiesMapToString(filter));
267 filter.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
269 Stream<ChampObject> retrievedVertices;
271 retrievedVertices = champApi.queryObjects(filter);
273 } catch (ChampTransactionException e) {
274 throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
277 List<Vertex> vertices = retrievedVertices.map(v -> vertexFromChampObject(v, type)).collect(Collectors.toList());
279 if (logger.isDebugEnabled()) {
280 logger.debug("Resulting vertex list: " + retrievedVertices);
283 // ...and return it to the caller.
287 private Object getRelKey(String id) {
289 // convert into Long if applicable . TODO : revisit in story NUC-304
291 key = Long.parseLong(id);
292 } catch (NumberFormatException e) {
293 // The id isn't a Long, leave it as a string
300 public Edge getEdge(String id, String type) throws CrudException {
302 if (logger.isDebugEnabled()) {
303 logger.debug("Get edge with id: " + id);
308 // Request the edge from the graph db.
309 Optional<ChampRelationship> relationship = champApi.retrieveRelationship(getRelKey(id));
312 if (relationship.isPresent() && relationship.get().getType().equals(type)) {
314 // Yup - return the result.
315 return edgeFromChampRelationship(relationship.get());
319 // We didn't find an edge with the supplied id, so throw an exception.
320 throw new CrudException("No edge with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
323 } catch (ChampUnmarshallingException | ChampTransactionException e) {
325 // Something went wrong, so throw an exception.
326 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
331 public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties) throws CrudException {
333 // For now, assume source and target are straight ids...
336 Optional<ChampObject> sourceObject = champApi.retrieveObject(Long.parseLong(source.getId().get()));
337 if (!sourceObject.isPresent() || !sourceObject.get().getType().equals(source.getType())) {
338 throw new CrudException("Error creating edge - source vertex with id " + source + " does not exist in graph data base",
339 javax.ws.rs.core.Response.Status.BAD_REQUEST);
342 Optional<ChampObject> targetObject = champApi.retrieveObject(Long.parseLong(target.getId().get()));
343 if (!targetObject.isPresent() || !targetObject.get().getType().equals(target.getType())) {
344 throw new CrudException("Error creating edge - target vertex with id " + target + " does not exist in graph data base",
345 javax.ws.rs.core.Response.Status.BAD_REQUEST);
348 // Now, create the ChampRelationship object for our edge and store it in
349 // the graph database.
350 return edgeFromChampRelationship(
351 champApi.storeRelationship(new ChampRelationship.Builder(sourceObject.get(), targetObject.get(), type).properties(properties).build()));
353 } catch (ChampMarshallingException | ChampObjectNotExistsException | ChampSchemaViolationException | ChampRelationshipNotExistsException
354 | ChampUnmarshallingException | NumberFormatException | ChampTransactionException e) {
356 throw new CrudException("Error creating edge: " + e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
361 public List<Edge> getEdges(String type, Map<String, Object> filter) throws CrudException {
363 filter.put(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString(), type);
365 Stream<ChampRelationship> retrievedRelationships;
367 retrievedRelationships = champApi.queryRelationships(filter);
369 } catch (ChampTransactionException e) {
370 throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
373 // Process the result stream from the Champ library into an Edge list, keeping only
374 // edges of the specified type.
375 List<Edge> edges = retrievedRelationships.map(r -> edgeFromChampRelationship(r)).collect(Collectors.toList());
381 public Edge updateEdge(Edge edge) throws CrudException {
383 if (logger.isDebugEnabled()) {
384 logger.debug("Update edge with id: " + edge.getId() + " with properties: " + propertiesMapToString(edge.getProperties()));
388 // Now, build the updated version of the Champ Relationship...
389 ChampRelationship updateRelationship = new ChampRelationship.Builder(
390 buildChampObject(edge.getSource().getId().get(), edge.getSource().getType(), edge.getSource().getProperties()),
391 buildChampObject(edge.getTarget().getId().get(), edge.getTarget().getType(), edge.getTarget().getProperties()), edge.getType())
392 .key(getRelKey(edge.getId().get())).properties(edge.getProperties()).build();
393 // ...and send it to the Champ library.
394 return edgeFromChampRelationship(champApi.replaceRelationship(updateRelationship));
396 } catch (ChampRelationshipNotExistsException ex) {
397 throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
398 } catch (NumberFormatException | ChampUnmarshallingException | ChampMarshallingException | ChampSchemaViolationException
399 | ChampTransactionException ex) {
401 throw new CrudException(ex.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
406 public void deleteVertex(String id, String type) throws CrudException {
410 // First, retrieve the vertex that we intend to delete.
411 Optional<ChampObject> retrievedVertex = champApi.retrieveObject(Long.parseLong(id));
414 if (!retrievedVertex.isPresent() || !retrievedVertex.get().getType().equals(type)) {
415 throw new CrudException("Failed to delete vertex with id: " + id + " - vertex does not exist.", javax.ws.rs.core.Response.Status.NOT_FOUND);
418 // Now, verify that there are no edges incident to the vertex (they must be deleted
420 Stream<ChampRelationship> relationships = champApi.retrieveRelationships(retrievedVertex.get());
422 if (relationships.count() > 0) {
423 throw new CrudException("Attempt to delete vertex with id " + id + " which has incident edges.", javax.ws.rs.core.Response.Status.BAD_REQUEST);
426 // Finally, we can attempt to delete our vertex.
427 champApi.deleteObject(Long.parseLong(id));
429 } catch (NumberFormatException | ChampUnmarshallingException | ChampObjectNotExistsException | ChampTransactionException e) {
431 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
436 public void deleteEdge(String id, String type) throws CrudException {
440 // First, retrieve the edge that we want to delete.
441 Optional<ChampRelationship> relationshipToDelete = champApi.retrieveRelationship(getRelKey(id));
444 if (!relationshipToDelete.isPresent() || !relationshipToDelete.get().getType().equals(type)) {
445 throw new CrudException("Failed to delete edge with id: " + id + " - edge does not exist", javax.ws.rs.core.Response.Status.NOT_FOUND);
448 // Now we can delete the edge.
449 champApi.deleteRelationship(relationshipToDelete.get());
451 } catch (ChampRelationshipNotExistsException | NumberFormatException | ChampUnmarshallingException | ChampTransactionException e) {
453 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
458 * This helper method generates a string representation of a properties map for logging purposes.
461 * - The properties map to be converted.
462 * @return - The log statement friendly conversion of the properties map.
464 private String propertiesMapToString(Map<String, Object> properties) {
466 StringBuilder sb = new StringBuilder();
469 for (String key : properties.keySet()) {
470 sb.append("(").append(key).append(" -> ").append(properties.get(key)).append(") ");
475 return sb.toString();
479 * This helper method constructs a {@link ChampObject} suitable for passing to the Champ library.
482 * - The type to assign to our ChampObject
484 * - The set of properties to assign to our ChampObject
485 * @return - A populated ChampObject
487 private ChampObject buildChampObject(String type, Map<String, Object> properties) {
489 ObjectBuildOrPropertiesStep objectInProgress = ChampObject.create().ofType(type).withoutKey();
491 for (String key : properties.keySet()) {
492 objectInProgress.withProperty(key, properties.get(key));
494 return objectInProgress.build();
498 * This helper method constructs a {@link ChampObject} suitable for passing to the Champ library.
501 * - Unique identifier for this object.
503 * - The type to assign to our ChampObject
505 * - The set of properties to assign to our ChampObject
506 * @return - A populated ChampObject
508 private ChampObject buildChampObject(String id, String type, Map<String, Object> properties) {
510 ObjectBuildOrPropertiesStep objectInProgress = ChampObject.create().ofType(type).withKey(Long.parseLong(id));
512 for (String key : properties.keySet()) {
513 objectInProgress.withProperty(key, properties.get(key));
515 return objectInProgress.build();
518 private Vertex vertexFromChampObject(ChampObject champObject, String type) {
520 // Get the identifier for this vertex from the Champ object.
521 Object id = champObject.getKey().orElse("");
523 // Start building our {@link Vertex} object.
524 Vertex.Builder vertexBuilder = new Vertex.Builder(type);
525 vertexBuilder.id(id.toString());
527 // Convert the properties associated with the Champ object into the form expected for
529 for (String key : champObject.getProperties().keySet()) {
530 vertexBuilder.property(key, champObject.getProperties().get(key));
534 return vertexBuilder.build();
538 * This helper method converts a {@link ChampRelationship} from the Champ library into an equivalent {@link Edge}
539 * object that is understood by the CRUD Service.
541 * @param relationship
542 * - The ChampRelationship object to be converted.
543 * @return - An Edge object corresponding to the supplied ChampRelationship
545 private Edge edgeFromChampRelationship(ChampRelationship relationship) {
547 // Populate the edge's id, if available.
548 Object relationshipId = relationship.getKey().orElse("");
550 Edge.Builder edgeBuilder = new Edge.Builder(relationship.getType()).id(relationshipId.toString());
551 edgeBuilder.source(vertexFromChampObject(relationship.getSource(),
552 relationship.getSource().getProperties().get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
553 ? relationship.getSource().getType()
554 : relationship.getSource().getProperties().get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()));
555 edgeBuilder.target(vertexFromChampObject(relationship.getTarget(),
556 relationship.getTarget().getProperties().get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
557 ? relationship.getTarget().getType()
558 : relationship.getTarget().getProperties().get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()));
560 for (String key : relationship.getProperties().keySet()) {
561 edgeBuilder.property(key, relationship.getProperties().get(key).toString());
564 return edgeBuilder.build();
568 * Performs any necessary shut down operations when the DAO is no longer needed.
570 public void close() {
572 if (champApi != null) {
574 logger.info(CrudServiceMsgs.STOPPING_CHAMP_DAO);
581 public String openTransaction() {
583 ChampTransaction transaction = champApi.openTransaction();
585 transactions.put(transaction.id(), transaction);
586 logger.info(CrudServiceMsgs.TRANSACTION, "Stored transaction " + transaction.id() + " in hashmap");
587 logger.info(CrudServiceMsgs.TRANSACTION, "Hash map contents:");
588 for (String key : transactions.keySet()) {
589 logger.info(CrudServiceMsgs.TRANSACTION, key);
591 return transaction.id();
595 public void commitTransaction(String id) throws CrudException {
598 champApi.commitTransaction(getTransaction(id));
599 } catch (ChampTransactionException e) {
600 throw new CrudException("Error while commiting transaction " + id, javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
602 transactions.remove(id);
606 public void rollbackTransaction(String id) throws CrudException {
609 champApi.rollbackTransaction(getTransaction(id));
610 } catch (ChampTransactionException e) {
611 throw new CrudException("Error while transaction rollback " + id, javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
613 transactions.remove(id);
616 private ChampTransaction getTransaction(String id) throws CrudException {
618 logger.info(CrudServiceMsgs.TRANSACTION, "Looking up transaction " + id);
619 if (transactions.containsKey(id)) {
620 logger.info(CrudServiceMsgs.TRANSACTION, "Found it!");
621 return (transactions.get(id));
623 logger.info(CrudServiceMsgs.TRANSACTION, "Didn't find transaction id " + id + ". Hash map contains: ");
624 for (String key : transactions.keySet()) {
625 logger.info(CrudServiceMsgs.TRANSACTION, key);
627 throw new CrudException("No open transaction with id: " + id, javax.ws.rs.core.Response.Status.NOT_FOUND);
632 public Vertex addVertex(String type, Map<String, Object> properties, String txId) throws CrudException {
633 if (logger.isDebugEnabled()) {
634 logger.debug("Add/update vertex: {label: " + type + " properties:" + propertiesMapToString(properties));
637 // Add the aai_node_type so that AAI can read the data created by gizmo
638 properties.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
640 // Create an object to represent our vertex in the format expected by the Champ library.
641 ChampObject objectToCreate = buildChampObject(type, properties);
645 // Ask the Champ library to store our vertex, placing the returned object into a
646 // list so that we can easily put that into our result object.
647 return vertexFromChampObject(champApi.storeObject(objectToCreate, Optional.of(getTransaction(txId))), type);
649 } catch (ChampMarshallingException | ChampSchemaViolationException | ChampObjectNotExistsException | ChampTransactionException e) {
651 // Something went wrong - throw an exception.
652 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
657 public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties, String txId) throws CrudException {
658 // For now, assume source and target are straight ids...
661 Optional<ChampObject> sourceObject = champApi.retrieveObject(Long.parseLong(source.getId().get()), Optional.of(getTransaction(txId)));
662 if (!sourceObject.isPresent() || !sourceObject.get().getType().equals(source.getType())) {
663 throw new CrudException("Error creating edge - source vertex with id " + source + " does not exist in graph data base",
664 javax.ws.rs.core.Response.Status.BAD_REQUEST);
667 Optional<ChampObject> targetObject = champApi.retrieveObject(Long.parseLong(target.getId().get()), Optional.of(getTransaction(txId)));
668 if (!targetObject.isPresent() || !targetObject.get().getType().equals(target.getType())) {
669 throw new CrudException("Error creating edge - target vertex with id " + target + " does not exist in graph data base",
670 javax.ws.rs.core.Response.Status.BAD_REQUEST);
673 // Now, create the ChampRelationship object for our edge and store it in
674 // the graph database.
675 return edgeFromChampRelationship(
676 champApi.storeRelationship(new ChampRelationship.Builder(sourceObject.get(), targetObject.get(), type).properties(properties).build(),
677 Optional.of(getTransaction(txId))));
679 } catch (ChampMarshallingException | ChampObjectNotExistsException | ChampSchemaViolationException | ChampTransactionException
680 | ChampRelationshipNotExistsException | ChampUnmarshallingException e) {
682 throw new CrudException("Error creating edge: " + e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
688 public Vertex updateVertex(String id, String type, Map<String, Object> properties, String txId) throws CrudException {
689 if (logger.isDebugEnabled()) {
690 logger.debug("Update vertex with id: " + id + " with properties: " + propertiesMapToString(properties));
692 // Add the aai_node_type so that AAI can read the data created by gizmo
693 properties.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
696 // Now, build the updated version of the Champ Object...
697 ChampObject updateObject = buildChampObject(id, type, properties);
698 // ...and send it to the Champ library.
699 return vertexFromChampObject(champApi.replaceObject(updateObject, Optional.of(getTransaction(txId))), type);
701 } catch (ChampObjectNotExistsException e) {
702 throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
703 } catch (NumberFormatException | ChampMarshallingException | ChampTransactionException | ChampSchemaViolationException e) {
704 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
709 public boolean transactionExists(String id) throws CrudException {
710 return transactions.containsKey(id);
714 public void deleteVertex(String id, String type, String txId) throws CrudException {
717 // First, retrieve the vertex that we intend to delete.
718 Optional<ChampObject> retrievedVertex = champApi.retrieveObject(Long.parseLong(id), Optional.of(getTransaction(txId)));
721 if (!retrievedVertex.isPresent() || !retrievedVertex.get().getType().equals(type)) {
722 throw new CrudException("Failed to delete vertex with id: " + id + " - vertex does not exist.", javax.ws.rs.core.Response.Status.NOT_FOUND);
725 // Now, verify that there are no edges incident to the vertex (they must be deleted
727 Stream<ChampRelationship> relationships = champApi.retrieveRelationships(retrievedVertex.get(), Optional.of(getTransaction(txId)));
729 if (relationships.count() > 0) {
730 throw new CrudException("Attempt to delete vertex with id " + id + " which has incident edges.", javax.ws.rs.core.Response.Status.BAD_REQUEST);
733 // Finally, we can attempt to delete our vertex.
734 champApi.deleteObject(Long.parseLong(id), Optional.of(getTransaction(txId)));
736 } catch (NumberFormatException | ChampUnmarshallingException | ChampObjectNotExistsException | ChampTransactionException e) {
738 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
744 public Edge updateEdge(Edge edge, String txId) throws CrudException {
745 if (logger.isDebugEnabled()) {
746 logger.debug("Update edge with id: " + edge.getId() + " with properties: " + propertiesMapToString(edge.getProperties()));
750 // Now, build the updated version of the Champ Relationship...
751 ChampRelationship updateRelationship = new ChampRelationship.Builder(
752 buildChampObject(edge.getSource().getId().get(), edge.getSource().getType(), edge.getSource().getProperties()),
753 buildChampObject(edge.getTarget().getId().get(), edge.getTarget().getType(), edge.getTarget().getProperties()), edge.getType())
754 .key(getRelKey(edge.getId().get())).properties(edge.getProperties()).build();
755 // ...and send it to the Champ library.
756 return edgeFromChampRelationship(champApi.replaceRelationship(updateRelationship, Optional.of(getTransaction(txId))));
758 } catch (ChampRelationshipNotExistsException ex) {
759 throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
760 } catch (NumberFormatException | ChampUnmarshallingException | ChampMarshallingException | ChampSchemaViolationException
761 | ChampTransactionException ex) {
763 throw new CrudException(ex.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
768 public void deleteEdge(String id, String type, String txId) throws CrudException {
771 // First, retrieve the edge that we want to delete.
772 Optional<ChampRelationship> relationshipToDelete = champApi.retrieveRelationship(getRelKey(id), Optional.of(getTransaction(txId)));
775 if (!relationshipToDelete.isPresent() || !relationshipToDelete.get().getType().equals(type)) {
776 throw new CrudException("Failed to delete edge with id: " + id + " - edge does not exist", javax.ws.rs.core.Response.Status.NOT_FOUND);
779 // Now we can delete the edge.
780 champApi.deleteRelationship(relationshipToDelete.get(), Optional.of(getTransaction(txId)));
782 } catch (ChampRelationshipNotExistsException | NumberFormatException | ChampUnmarshallingException | ChampTransactionException e) {
784 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
790 public Edge getEdge(String id, String type, String txId) throws CrudException {
791 if (logger.isDebugEnabled()) {
792 logger.debug("Get edge with id: " + id);
797 // Request the edge from the graph db.
798 Optional<ChampRelationship> relationship = champApi.retrieveRelationship(getRelKey(id), Optional.of(getTransaction(txId)));
801 if (relationship.isPresent() && relationship.get().getType().equals(type)) {
803 // Yup - return the result.
804 return edgeFromChampRelationship(relationship.get());
808 // We didn't find an edge with the supplied id, so throw an exception.
809 throw new CrudException("No edge with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
812 } catch (ChampUnmarshallingException | ChampTransactionException e) {
814 // Something went wrong, so throw an exception.
815 throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);