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.crud.service;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
28 import javax.ws.rs.core.EntityTag;
29 import javax.ws.rs.core.HttpHeaders;
30 import javax.ws.rs.core.Response.Status;
31 import org.apache.commons.lang3.tuple.ImmutablePair;
32 import org.onap.aai.restclient.client.OperationResult;
33 import org.onap.crud.dao.GraphDao;
34 import org.onap.crud.dao.champ.ChampEdgeSerializer;
35 import org.onap.crud.dao.champ.ChampVertexSerializer;
36 import org.onap.crud.entity.Edge;
37 import org.onap.crud.entity.Vertex;
38 import org.onap.crud.exception.CrudException;
39 import org.onap.crud.parser.BulkPayload;
40 import org.onap.crud.parser.CrudResponseBuilder;
41 import org.onap.crud.parser.EdgePayload;
42 import org.onap.crud.parser.VertexPayload;
43 import org.onap.crud.parser.util.EdgePayloadUtil;
44 import org.onap.crud.util.CrudServiceUtil;
45 import org.onap.schema.validation.OxmModelValidator;
46 import org.onap.schema.validation.RelationshipSchemaValidator;
47 import com.google.gson.Gson;
48 import com.google.gson.GsonBuilder;
49 import com.google.gson.JsonElement;
50 import com.google.gson.reflect.TypeToken;
51 import net.dongliu.gson.GsonJava8TypeAdapterFactory;
53 public abstract class AbstractGraphDataService {
54 protected GraphDao daoForGet;
55 protected GraphDao dao;
57 public AbstractGraphDataService() throws CrudException {
58 CrudServiceUtil.loadModels();
61 public ImmutablePair<EntityTag, String> getEdge(String version, String id, String type, Map<String, String> queryParams) throws CrudException {
62 RelationshipSchemaValidator.validateType(version, type);
63 OperationResult operationResult = daoForGet.getEdge(id, type, queryParams);
64 EntityTag entityTag = CrudServiceUtil.getETagFromHeader(operationResult.getHeaders());
65 Edge edge = Edge.fromJson(operationResult.getResult());
66 return new ImmutablePair<>(entityTag, CrudResponseBuilder.buildGetEdgeResponse(RelationshipSchemaValidator.validateOutgoingPayload(version, edge), version));
69 public ImmutablePair<EntityTag, String> getEdges(String version, String type, Map<String, String> filter) throws CrudException {
70 Gson champGson = new GsonBuilder()
71 .registerTypeAdapterFactory(new GsonJava8TypeAdapterFactory())
72 .registerTypeAdapter(Vertex.class, new ChampVertexSerializer())
73 .registerTypeAdapter(Edge.class, new ChampEdgeSerializer()).create();
74 RelationshipSchemaValidator.validateType(version, type);
75 OperationResult operationResult = daoForGet.getEdges(type, RelationshipSchemaValidator.resolveCollectionfilter(version, type, filter));
76 List<Edge> items = champGson.fromJson(operationResult.getResult(), new TypeToken<List<Edge>>() {
78 EntityTag entityTag = CrudServiceUtil.getETagFromHeader(operationResult.getHeaders());
79 return new ImmutablePair<>(entityTag, CrudResponseBuilder.buildGetEdgesResponse(items, version));
82 public ImmutablePair<EntityTag, String> getVertex(String version, String id, String type, Map<String, String> queryParams) throws CrudException {
83 type = OxmModelValidator.resolveCollectionType(version, type);
84 OperationResult vertexOpResult = daoForGet.getVertex(id, type, version, queryParams);
85 Vertex vertex = Vertex.fromJson(vertexOpResult.getResult(), version);
86 List<Edge> edges = daoForGet.getVertexEdges(id, queryParams, null);
87 EntityTag entityTag = CrudServiceUtil.getETagFromHeader(vertexOpResult.getHeaders());
88 return new ImmutablePair<>(entityTag, CrudResponseBuilder.buildGetVertexResponse(OxmModelValidator.validateOutgoingPayload(version, vertex), edges,
92 public ImmutablePair<EntityTag, String> getVertices(String version, String type, Map<String, String> filter, Set<String> properties) throws CrudException {
93 type = OxmModelValidator.resolveCollectionType(version, type);
94 OperationResult operationResult = daoForGet.getVertices(type, OxmModelValidator.resolveCollectionfilter(version, type, filter), properties, version);
95 List<Vertex> vertices = Vertex.collectionFromJson(operationResult.getResult(), version);
96 EntityTag entityTag = CrudServiceUtil.getETagFromHeader(operationResult.getHeaders());
97 return new ImmutablePair<>(entityTag, CrudResponseBuilder.buildGetVerticesResponse(vertices, version));
100 public String addBulk(String version, BulkPayload payload, HttpHeaders headers) throws CrudException {
101 HashMap<String, Vertex> vertices = new HashMap<>();
102 HashMap<String, Edge> edges = new HashMap<>();
104 String txId = dao.openTransaction();
107 // Step 1. Handle edge deletes (must happen before vertex deletes)
108 for (JsonElement v : payload.getRelationships()) {
109 List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
110 v.getAsJsonObject().entrySet());
112 if (entries.size() != 2) {
113 throw new CrudException("", Status.BAD_REQUEST);
115 Map.Entry<String, JsonElement> opr = entries.get(0);
116 Map.Entry<String, JsonElement> item = entries.get(1);
117 EdgePayload edgePayload = EdgePayload.fromJson(item.getValue().getAsJsonObject().toString());
119 if (opr.getValue().getAsString().equalsIgnoreCase("delete")) {
120 deleteBulkEdge(edgePayload.getId(), version, txId);
124 // Step 2: Handle vertex deletes
125 for (JsonElement v : payload.getObjects()) {
126 List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
127 v.getAsJsonObject().entrySet());
129 if (entries.size() != 2) {
130 throw new CrudException("", Status.BAD_REQUEST);
133 Map.Entry<String, JsonElement> opr = entries.get(0);
134 Map.Entry<String, JsonElement> item = entries.get(1);
135 VertexPayload vertexPayload = VertexPayload.fromJson(item.getValue().getAsJsonObject().toString());
137 if (opr.getValue().getAsString().equalsIgnoreCase("delete")) {
138 String type = OxmModelValidator.resolveCollectionType(version, vertexPayload.getType());
139 deleteBulkVertex(vertexPayload.getId(), version, type, txId);
143 // Step 3: Handle vertex add/modify (must happen before edge adds)
144 for (JsonElement v : payload.getObjects()) {
145 List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
146 v.getAsJsonObject().entrySet());
148 if (entries.size() != 2) {
149 throw new CrudException("", Status.BAD_REQUEST);
151 Map.Entry<String, JsonElement> opr = entries.get(0);
152 Map.Entry<String, JsonElement> item = entries.get(1);
153 VertexPayload vertexPayload = VertexPayload.fromJson(item.getValue().getAsJsonObject().toString());
156 if (opr.getValue().getAsString().equalsIgnoreCase("add")) {
157 vertexPayload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(vertexPayload.getProperties(),
159 Vertex validatedVertex = OxmModelValidator.validateIncomingUpsertPayload(null, version, vertexPayload.getType(),
160 vertexPayload.getProperties());
161 Vertex persistedVertex = addBulkVertex(validatedVertex, version, txId);
162 Vertex outgoingVertex = OxmModelValidator.validateOutgoingPayload(version, persistedVertex);
163 vertices.put(item.getKey(), outgoingVertex);
167 else if (opr.getValue().getAsString().equalsIgnoreCase("modify")) {
168 vertexPayload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(vertexPayload.getProperties(),
170 Vertex validatedVertex = OxmModelValidator.validateIncomingUpsertPayload(vertexPayload.getId(), version,
171 vertexPayload.getType(), vertexPayload.getProperties());
172 Vertex persistedVertex = updateBulkVertex(validatedVertex, vertexPayload.getId(), version, txId);
173 Vertex outgoingVertex = OxmModelValidator.validateOutgoingPayload(version, persistedVertex);
174 vertices.put(item.getKey(), outgoingVertex);
178 else if (opr.getValue().getAsString().equalsIgnoreCase("patch")) {
179 if ( (vertexPayload.getId() == null) || (vertexPayload.getType() == null) ) {
180 throw new CrudException("id and type must be specified for patch request", Status.BAD_REQUEST);
183 vertexPayload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(vertexPayload.getProperties(),
186 OperationResult existingVertexOpResult = dao.getVertex(vertexPayload.getId(), OxmModelValidator.resolveCollectionType(version, vertexPayload.getType()), version, new HashMap<String, String>());
187 Vertex existingVertex = Vertex.fromJson(existingVertexOpResult.getResult(), version);
188 Vertex validatedVertex = OxmModelValidator.validateIncomingPatchPayload(vertexPayload.getId(),
189 version, vertexPayload.getType(), vertexPayload.getProperties(), existingVertex);
190 Vertex persistedVertex = updateBulkVertex(validatedVertex, vertexPayload.getId(), version, txId);
191 Vertex outgoingVertex = OxmModelValidator.validateOutgoingPayload(version, persistedVertex);
192 vertices.put(item.getKey(), outgoingVertex);
196 // Step 4: Handle edge add/modify
197 for (JsonElement v : payload.getRelationships()) {
198 List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
199 v.getAsJsonObject().entrySet());
201 if (entries.size() != 2) {
202 throw new CrudException("", Status.BAD_REQUEST);
204 Map.Entry<String, JsonElement> opr = entries.get(0);
205 Map.Entry<String, JsonElement> item = entries.get(1);
206 EdgePayload edgePayload = EdgePayload.fromJson(item.getValue().getAsJsonObject().toString());
209 if (opr.getValue().getAsString().equalsIgnoreCase("add")
210 || opr.getValue().getAsString().equalsIgnoreCase("modify")
211 || opr.getValue().getAsString().equalsIgnoreCase("patch")) {
214 if (opr.getValue().getAsString().equalsIgnoreCase("add")) {
215 // Fix the source/destination
216 if (edgePayload.getSource().startsWith("$")) {
217 Vertex source = vertices.get(edgePayload.getSource().substring(1));
218 if (source == null) {
219 throw new CrudException("Not able to find vertex: " + edgePayload.getSource().substring(1),
220 Status.INTERNAL_SERVER_ERROR);
223 .setSource("services/inventory/" + version + "/" + source.getType() + "/" + source.getId().get());
225 if (edgePayload.getTarget().startsWith("$")) {
226 Vertex target = vertices.get(edgePayload.getTarget().substring(1));
227 if (target == null) {
228 throw new CrudException("Not able to find vertex: " + edgePayload.getTarget().substring(1),
229 Status.INTERNAL_SERVER_ERROR);
232 .setTarget("services/inventory/" + version + "/" + target.getType() + "/" + target.getId().get());
235 // If the type isn't set, resolve it based on on the sourece and target vertex types
236 if (edgePayload.getType() == null || edgePayload.getType().isEmpty()) {
237 edgePayload.setType(CrudServiceUtil.determineEdgeType(edgePayload, version));
240 List<Edge> sourceVertexEdges =
241 EdgePayloadUtil.filterEdgesByRelatedVertexAndType(EdgePayloadUtil.getVertexNodeType(edgePayload.getSource()), edgePayload.getType(),
242 dao.getVertexEdges(EdgePayloadUtil.getVertexNodeId(edgePayload.getSource()), null, txId));
244 List<Edge> targetVertexEdges =
245 EdgePayloadUtil.filterEdgesByRelatedVertexAndType(EdgePayloadUtil.getVertexNodeType(edgePayload.getTarget()), edgePayload.getType(),
246 dao.getVertexEdges(EdgePayloadUtil.getVertexNodeId(edgePayload.getTarget()), null, txId));
248 validatedEdge = RelationshipSchemaValidator.validateIncomingAddPayload(version, edgePayload.getType(), edgePayload, sourceVertexEdges,
250 persistedEdge = addBulkEdge(validatedEdge, version, txId);
251 } else if (opr.getValue().getAsString().equalsIgnoreCase("modify")) {
252 Edge edge = dao.getEdge(edgePayload.getId(), txId);
254 // If the type isn't set, resolve it based on on the sourece and target vertex types
255 if (edgePayload.getType() == null || edgePayload.getType().isEmpty()) {
256 edgePayload.setType(edge.getType());
259 // load source and target vertex relationships for validation
260 List<Edge> sourceVertexEdges =
261 EdgePayloadUtil.filterEdgesByRelatedVertexAndType(EdgePayloadUtil.getVertexNodeType(edgePayload.getSource()), edgePayload.getType(),
262 dao.getVertexEdges(EdgePayloadUtil.getVertexNodeId(edgePayload.getSource()), null, txId));
264 List<Edge> targetVertexEdges =
265 EdgePayloadUtil.filterEdgesByRelatedVertexAndType(EdgePayloadUtil.getVertexNodeType(edgePayload.getTarget()), edgePayload.getType(),
266 dao.getVertexEdges(EdgePayloadUtil.getVertexNodeId(edgePayload.getTarget()), null, txId));
269 validatedEdge = RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, edgePayload, edgePayload.getType(), sourceVertexEdges, targetVertexEdges);
270 persistedEdge = updateBulkEdge(validatedEdge, version, txId);
272 if (edgePayload.getId() == null) {
273 throw new CrudException("id must be specified for patch request", Status.BAD_REQUEST);
275 Edge existingEdge = dao.getEdge(edgePayload.getId(), txId);
277 // If the type isn't set, resolve it based on on the sourece and target vertex types
278 if (edgePayload.getType() == null || edgePayload.getType().isEmpty()) {
279 edgePayload.setType(existingEdge.getType());
282 Edge patchedEdge = RelationshipSchemaValidator.validateIncomingPatchPayload(existingEdge, version, edgePayload);
283 persistedEdge = updateBulkEdge(patchedEdge, version, txId);
287 Edge outgoingEdge = RelationshipSchemaValidator.validateOutgoingPayload(version, persistedEdge);
288 edges.put(item.getKey(), outgoingEdge);
292 // commit transaction
293 dao.commitTransaction(txId);
294 } catch (CrudException ex) {
295 dao.rollbackTransaction(txId);
297 } catch (Exception ex) {
298 dao.rollbackTransaction(txId);
301 if (dao.transactionExists(txId)) {
302 dao.rollbackTransaction(txId);
306 return CrudResponseBuilder.buildUpsertBulkResponse(vertices, edges, version, payload);
310 public abstract ImmutablePair<EntityTag, String> addVertex(String version, String type, VertexPayload payload)
311 throws CrudException;
312 public abstract ImmutablePair<EntityTag, String> updateVertex(String version, String id, String type,
313 VertexPayload payload) throws CrudException;
314 public abstract ImmutablePair<EntityTag, String> patchVertex(String version, String id, String type,
315 VertexPayload payload) throws CrudException;
316 public abstract String deleteVertex(String version, String id, String type) throws CrudException;
317 public abstract ImmutablePair<EntityTag, String> addEdge(String version, String type, EdgePayload payload)
318 throws CrudException;
319 public abstract String deleteEdge(String version, String id, String type) throws CrudException;
320 public abstract ImmutablePair<EntityTag, String> updateEdge(String version, String id, String type,
321 EdgePayload payload) throws CrudException;
322 public abstract ImmutablePair<EntityTag, String> patchEdge(String version, String id, String type,
323 EdgePayload payload) throws CrudException;
325 protected abstract Vertex addBulkVertex(Vertex vertex, String version, String dbTransId) throws CrudException;
326 protected abstract Vertex updateBulkVertex(Vertex vertex, String id, String version, String dbTransId) throws CrudException;
327 protected abstract void deleteBulkVertex(String id, String version, String type, String dbTransId) throws CrudException;
329 protected abstract Edge addBulkEdge(Edge edge, String version, String dbTransId) throws CrudException;
330 protected abstract Edge updateBulkEdge(Edge edge, String version, String dbTransId) throws CrudException;
331 protected abstract void deleteBulkEdge(String id, String version, String dbTransId) throws CrudException;