/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. * Copyright © 2017-2018 Amdocs * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.onap.crud.dao.champ; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response.Status; import org.onap.aai.restclient.client.OperationResult; import org.onap.crud.dao.GraphDao; import org.onap.crud.entity.Edge; import org.onap.crud.entity.Vertex; import org.onap.crud.exception.CrudException; import org.onap.crud.service.BulkPayload; import org.onap.crud.service.EdgePayload; import org.onap.crud.service.VertexPayload; import org.onap.crud.util.CrudServiceUtil; import org.onap.schema.OxmModelValidator; import org.onap.schema.RelationshipSchemaValidator; public class ChampBulkPayload { public static String ADD_OP = "add"; public static String UPDATE_OP = "modify"; public static String DELETE_OP = "delete"; public static String PATCH_OP = "patch"; private List edgeDeleteOps = new ArrayList(); private List vertexDeleteOps = new ArrayList(); private List vertexAddModifyOps = new ArrayList(); private List edgeAddModifyOps = new ArrayList(); private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); public String toJson() { return gson.toJson(this); } public static ChampBulkPayload fromJson(String payload) { return gson.fromJson(payload, ChampBulkPayload.class); } public List getEdgeDeleteOps() { return edgeDeleteOps; } public void setEdgeDeleteOps(List ops) { this.edgeDeleteOps = ops; } public List getVertexDeleteOps() { return vertexDeleteOps; } public void setVertexDeleteOps(List ops) { this.vertexDeleteOps = ops; } public List getVertexAddModifyOps() { return vertexAddModifyOps; } public void setVertexAddModifyOps(List ops) { this.vertexAddModifyOps = ops; } public List getEdgeAddModifyOps() { return edgeAddModifyOps; } public void setEdgeAddModifyOps(List ops) { this.edgeAddModifyOps = ops; } public void fromGizmoPayload(BulkPayload gizmoPayload, String version, HttpHeaders headers, GraphDao champDao) throws CrudException { edgeDeleteOps = new ArrayList(); vertexDeleteOps = new ArrayList(); vertexAddModifyOps = new ArrayList(); edgeAddModifyOps = new ArrayList(); Map addedVertexes = new HashMap(); // Step 1. Extract edge deletes for (JsonElement v : gizmoPayload.getRelationships()) { List> entries = new ArrayList>( v.getAsJsonObject().entrySet()); if (entries.size() != 2) { throw new CrudException("", Status.BAD_REQUEST); } Map.Entry opr = entries.get(0); Map.Entry item = entries.get(1); EdgePayload edgePayload = EdgePayload.fromJson(item.getValue().getAsJsonObject().toString()); if (opr.getValue().getAsString().equalsIgnoreCase("delete")) { ChampBulkOp champOp = new ChampBulkOp(); champOp.setId(edgePayload.getId()); champOp.setOperation(DELETE_OP); edgeDeleteOps.add(champOp); } } // Step 2: Extract vertex deletes for (JsonElement v : gizmoPayload.getObjects()) { List> entries = new ArrayList>( v.getAsJsonObject().entrySet()); if (entries.size() != 2) { throw new CrudException("", Status.BAD_REQUEST); } Map.Entry opr = entries.get(0); Map.Entry item = entries.get(1); VertexPayload vertexPayload = VertexPayload.fromJson(item.getValue().getAsJsonObject().toString()); if (opr.getValue().getAsString().equalsIgnoreCase("delete")) { String type = OxmModelValidator.resolveCollectionType(version, vertexPayload.getType()); ChampBulkOp champOp = new ChampBulkOp(); champOp.setId(vertexPayload.getId()); champOp.setOperation(DELETE_OP); champOp.setType(type); vertexDeleteOps.add(champOp); } } // Step 3: Extract vertex add/modify for (JsonElement v : gizmoPayload.getObjects()) { List> entries = new ArrayList>( v.getAsJsonObject().entrySet()); if (entries.size() != 2) { throw new CrudException("", Status.BAD_REQUEST); } Map.Entry opr = entries.get(0); Map.Entry item = entries.get(1); VertexPayload vertexPayload = VertexPayload.fromJson(item.getValue().getAsJsonObject().toString()); // Add vertex if (opr.getValue().getAsString().equalsIgnoreCase("add")) { vertexPayload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(vertexPayload.getProperties(), headers, true)); Vertex validatedVertex = OxmModelValidator.validateIncomingUpsertPayload(null, version, vertexPayload.getType(), vertexPayload.getProperties()); validatedVertex.getProperties().put(OxmModelValidator.Metadata.NODE_TYPE.propertyName(), vertexPayload.getType()); ChampBulkOp champOp = new ChampBulkOp(); champOp.setLabel(item.getKey()); champOp.setOperation(ADD_OP); champOp.setType(vertexPayload.getType()); champOp.setProperties(validatedVertex.getProperties()); vertexAddModifyOps.add(champOp); } // Update vertex else if (opr.getValue().getAsString().equalsIgnoreCase("modify")) { vertexPayload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(vertexPayload.getProperties(), headers, false)); Vertex validatedVertex = OxmModelValidator.validateIncomingUpsertPayload(vertexPayload.getId(), version, vertexPayload.getType(), vertexPayload.getProperties()); validatedVertex.getProperties().put(OxmModelValidator.Metadata.NODE_TYPE.propertyName(), vertexPayload.getType()); ChampBulkOp champOp = new ChampBulkOp(); champOp.setLabel(item.getKey()); champOp.setId(vertexPayload.getId()); champOp.setOperation(UPDATE_OP); champOp.setType(vertexPayload.getType()); champOp.setProperties(validatedVertex.getProperties()); vertexAddModifyOps.add(champOp); } // Patch vertex else if (opr.getValue().getAsString().equalsIgnoreCase("patch")) { if ( (vertexPayload.getId() == null) || (vertexPayload.getType() == null) ) { throw new CrudException("id and type must be specified for patch request", Status.BAD_REQUEST); } vertexPayload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(vertexPayload.getProperties(), headers, false)); OperationResult existingVertexOpResult = champDao.getVertex(vertexPayload.getId(), OxmModelValidator.resolveCollectionType(version, vertexPayload.getType()), version, new HashMap()); Vertex existingVertex = Vertex.fromJson(existingVertexOpResult.getResult(), version); Vertex validatedVertex = OxmModelValidator.validateIncomingPatchPayload(vertexPayload.getId(), version, vertexPayload.getType(), vertexPayload.getProperties(), existingVertex); validatedVertex.getProperties().put(OxmModelValidator.Metadata.NODE_TYPE.propertyName(), vertexPayload.getType()); ChampBulkOp champOp = new ChampBulkOp(); champOp.setLabel(item.getKey()); champOp.setId(vertexPayload.getId()); champOp.setOperation(UPDATE_OP); champOp.setType(vertexPayload.getType()); champOp.setProperties(validatedVertex.getProperties()); vertexAddModifyOps.add(champOp); } addedVertexes.put(item.getKey(), "services/inventory/" + version + "/" + vertexPayload.getType()+ "/" + item.getKey()); } // Step 4: Extract edge add/modify for (JsonElement v : gizmoPayload.getRelationships()) { List> entries = new ArrayList>( v.getAsJsonObject().entrySet()); if (entries.size() != 2) { throw new CrudException("", Status.BAD_REQUEST); } Map.Entry opr = entries.get(0); Map.Entry item = entries.get(1); EdgePayload edgePayload = EdgePayload.fromJson(item.getValue().getAsJsonObject().toString()); // Add/Update edge if (opr.getValue().getAsString().equalsIgnoreCase("add") || opr.getValue().getAsString().equalsIgnoreCase("modify") || opr.getValue().getAsString().equalsIgnoreCase("patch")) { ChampBulkOp champOp = new ChampBulkOp(); champOp.setLabel(item.getKey()); if (opr.getValue().getAsString().equalsIgnoreCase("add")) { // If the source/target is a vertex that hasn't been created yet, get the types from the map String sourceUrl = edgePayload.getSource(); String targetUrl = edgePayload.getTarget(); edgePayload.setSource(resolveUrl(edgePayload.getSource(), addedVertexes)); edgePayload.setTarget(resolveUrl(edgePayload.getTarget(), addedVertexes)); // If the type isn't set, resolve it based on on the source and target vertex types if (edgePayload.getType() == null || edgePayload.getType().isEmpty()) { edgePayload.setType(CrudServiceUtil.determineEdgeType(edgePayload, version)); } champOp.setType(edgePayload.getType()); Edge validatedEdge = RelationshipSchemaValidator.validateIncomingAddPayload(version, edgePayload.getType(), edgePayload); champOp.setOperation(ADD_OP); champOp.setProperties(validatedEdge.getProperties()); champOp.setSource(sourceUrl.substring(sourceUrl.lastIndexOf('/') + 1)); champOp.setTarget(targetUrl.substring(targetUrl.lastIndexOf('/') + 1)); } else if (opr.getValue().getAsString().equalsIgnoreCase("modify")) { Edge edge = champDao.getEdge(edgePayload.getId()); if (edgePayload.getType() == null || edgePayload.getType().isEmpty()) { edgePayload.setType(edge.getType()); } champOp.setType(edgePayload.getType()); Edge validatedEdge = RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, edgePayload); champOp.setOperation(UPDATE_OP); champOp.setId(edgePayload.getId()); champOp.setProperties(validatedEdge.getProperties()); champOp.setSource(edge.getSource().getId().get()); champOp.setTarget(edge.getTarget().getId().get()); } else { if (edgePayload.getId() == null) { throw new CrudException("id must be specified for patch request", Status.BAD_REQUEST); } Edge existingEdge = champDao.getEdge(edgePayload.getId()); if (edgePayload.getType() == null || edgePayload.getType().isEmpty()) { edgePayload.setType(existingEdge.getType()); } champOp.setType(edgePayload.getType()); Edge patchedEdge = RelationshipSchemaValidator.validateIncomingPatchPayload(existingEdge, version, edgePayload); champOp.setOperation(UPDATE_OP); champOp.setId(edgePayload.getId()); champOp.setProperties(patchedEdge.getProperties()); champOp.setSource(existingEdge.getSource().getId().get()); champOp.setTarget(existingEdge.getTarget().getId().get()); } edgeAddModifyOps.add(champOp); } } } private String resolveUrl(String vertexUrl, Map addedVertexes) throws CrudException { if (vertexUrl.startsWith("$")) { String key = vertexUrl.substring(1); if (addedVertexes.get(key) != null) { return addedVertexes.get(key); } throw new CrudException("Unable to resolve vertex " + key, Status.BAD_REQUEST); } return vertexUrl; } }