diff options
author | 2019-02-13 10:29:59 -0500 | |
---|---|---|
committer | 2019-02-13 10:30:26 -0500 | |
commit | f60a17c6abb6deef1c24f917488745cbc6e6a566 (patch) | |
tree | 3f7e612e4c1c0bcb435e6bbc851f09e8baa3afb7 /src/main/java/org/onap/crud/dao | |
parent | 0c40bcde9facc109ceb8dabb91156df2b4fb4129 (diff) |
Performance Improvements for Gizmo bulk API
Use bulk operations with Gizmo/Champ to improve performance.
Also allows for HA by allowing Champ to operate in stateless mode
Change-Id: I63bbbf8d6071cecb4b22110c477d7dc592026200
Issue-ID: AAI-2147
Signed-off-by: Serban Popescu <serban.popescu@amdocs.com>
Diffstat (limited to 'src/main/java/org/onap/crud/dao')
5 files changed, 694 insertions, 70 deletions
diff --git a/src/main/java/org/onap/crud/dao/GraphDao.java b/src/main/java/org/onap/crud/dao/GraphDao.java index 7cb3d4c..867cf56 100644 --- a/src/main/java/org/onap/crud/dao/GraphDao.java +++ b/src/main/java/org/onap/crud/dao/GraphDao.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import org.onap.aai.restclient.client.OperationResult; +import org.onap.crud.dao.champ.ChampBulkPayload; import org.onap.crud.entity.Edge; import org.onap.crud.entity.Vertex; import org.onap.crud.exception.CrudException; @@ -91,7 +92,7 @@ public interface GraphDao { * @throws CrudException */ public OperationResult getEdge(String id, String type, Map<String, String> queryParams) throws CrudException; - + /** * Retrieve a collection of {@link Edge} objects with a given type and which * match a set of supplied filter parameters. @@ -187,7 +188,7 @@ public interface GraphDao { public Vertex addVertex(String type, Map<String, Object> properties, String version, String txId) throws CrudException; public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties, String version, String txId) - throws CrudException; + throws CrudException; public Vertex updateVertex(String id, String type, Map<String, Object> properties, String version, String txId) throws CrudException; @@ -198,6 +199,8 @@ public interface GraphDao { public void deleteEdge(String id, String txId) throws CrudException; public Edge getEdge(String id, String txId) throws CrudException; - + public Edge getEdge(String id) throws CrudException; + + public OperationResult bulkOperation(ChampBulkPayload champPayload) throws CrudException; } diff --git a/src/main/java/org/onap/crud/dao/champ/ChampBulkOp.java b/src/main/java/org/onap/crud/dao/champ/ChampBulkOp.java new file mode 100644 index 0000000..9f7fffe --- /dev/null +++ b/src/main/java/org/onap/crud/dao/champ/ChampBulkOp.java @@ -0,0 +1,116 @@ +/** + * ============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 java.util.HashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class ChampBulkOp { + private static final Gson gson = new GsonBuilder().create(); + + private String operation; + private String id; + private String type; + private String label; + private String source; + private String target; + private Map<String, Object> properties; + + + public String toJson() { + return gson.toJson(this); + } + + public static ChampBulkOp fromJson(String jsonString) { + return gson.fromJson(jsonString, ChampBulkOp.class); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public Object getProperty(String key) { + return properties.get(key); + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + + public void setProperty(String key, String value) { + if (properties == null) { + properties = new HashMap<String,Object>(); + } + + properties.put(key, value); + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getTarget() { + return target; + } + + public void setTarget(String target) { + this.target = target; + } +} diff --git a/src/main/java/org/onap/crud/dao/champ/ChampBulkPayload.java b/src/main/java/org/onap/crud/dao/champ/ChampBulkPayload.java new file mode 100644 index 0000000..e00bdd2 --- /dev/null +++ b/src/main/java/org/onap/crud/dao/champ/ChampBulkPayload.java @@ -0,0 +1,316 @@ +/** + * ============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<ChampBulkOp> edgeDeleteOps = new ArrayList<ChampBulkOp>(); + private List<ChampBulkOp> vertexDeleteOps = new ArrayList<ChampBulkOp>(); + private List<ChampBulkOp> vertexAddModifyOps = new ArrayList<ChampBulkOp>(); + private List<ChampBulkOp> edgeAddModifyOps = new ArrayList<ChampBulkOp>(); + + 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<ChampBulkOp> getEdgeDeleteOps() { + return edgeDeleteOps; + } + + public void setEdgeDeleteOps(List<ChampBulkOp> ops) { + this.edgeDeleteOps = ops; + } + + public List<ChampBulkOp> getVertexDeleteOps() { + return vertexDeleteOps; + } + + public void setVertexDeleteOps(List<ChampBulkOp> ops) { + this.vertexDeleteOps = ops; + } + + public List<ChampBulkOp> getVertexAddModifyOps() { + return vertexAddModifyOps; + } + + public void setVertexAddModifyOps(List<ChampBulkOp> ops) { + this.vertexAddModifyOps = ops; + } + + public List<ChampBulkOp> getEdgeAddModifyOps() { + return edgeAddModifyOps; + } + + public void setEdgeAddModifyOps(List<ChampBulkOp> ops) { + this.edgeAddModifyOps = ops; + } + + public void fromGizmoPayload(BulkPayload gizmoPayload, String version, HttpHeaders headers, GraphDao champDao) throws CrudException { + edgeDeleteOps = new ArrayList<ChampBulkOp>(); + vertexDeleteOps = new ArrayList<ChampBulkOp>(); + vertexAddModifyOps = new ArrayList<ChampBulkOp>(); + edgeAddModifyOps = new ArrayList<ChampBulkOp>(); + + Map<String,String> addedVertexes = new HashMap<String,String>(); + + // Step 1. Extract edge deletes + for (JsonElement v : gizmoPayload.getRelationships()) { + List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>( + v.getAsJsonObject().entrySet()); + + if (entries.size() != 2) { + throw new CrudException("", Status.BAD_REQUEST); + } + Map.Entry<String, JsonElement> opr = entries.get(0); + Map.Entry<String, JsonElement> 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<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>( + v.getAsJsonObject().entrySet()); + + if (entries.size() != 2) { + throw new CrudException("", Status.BAD_REQUEST); + } + + Map.Entry<String, JsonElement> opr = entries.get(0); + Map.Entry<String, JsonElement> 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<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>( + v.getAsJsonObject().entrySet()); + + if (entries.size() != 2) { + throw new CrudException("", Status.BAD_REQUEST); + } + Map.Entry<String, JsonElement> opr = entries.get(0); + Map.Entry<String, JsonElement> 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<String, String>()); + + 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<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>( + v.getAsJsonObject().entrySet()); + + if (entries.size() != 2) { + throw new CrudException("", Status.BAD_REQUEST); + } + Map.Entry<String, JsonElement> opr = entries.get(0); + Map.Entry<String, JsonElement> 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<String, String> 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; + } +} diff --git a/src/main/java/org/onap/crud/dao/champ/ChampBulkPayloadResponse.java b/src/main/java/org/onap/crud/dao/champ/ChampBulkPayloadResponse.java new file mode 100644 index 0000000..3f58c8e --- /dev/null +++ b/src/main/java/org/onap/crud/dao/champ/ChampBulkPayloadResponse.java @@ -0,0 +1,172 @@ +/** + * ============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 java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.onap.crud.entity.Edge; +import org.onap.crud.entity.Vertex; +import org.onap.crud.exception.CrudException; +import org.onap.schema.OxmModelValidator; +import org.onap.schema.RelationshipSchemaValidator; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class ChampBulkPayloadResponse { + + private HashMap<String, Vertex> vertices = new HashMap<>(); + private HashMap<String, Edge> edges = new HashMap<>(); + + + @Expose + @SerializedName(value = "objects") + private List<JsonElement> objects = new ArrayList<JsonElement>(); + + @Expose + @SerializedName(value = "relationships") + private List<JsonElement> relationships = new ArrayList<JsonElement>(); + + + + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().excludeFieldsWithoutExposeAnnotation() + .create(); + + + public String toJson() { + return gson.toJson(this); + } + + public static ChampBulkPayloadResponse fromJson(String payload) { + ChampBulkPayloadResponse response = gson.fromJson(payload, ChampBulkPayloadResponse.class); + return response; + } + + + + public void populateChampData(String version) throws CrudException { + + for (JsonElement object : this.getObjects()) { + + JsonObject champObject = object.getAsJsonObject(); + String itemKey = champObject.get("label").getAsString(); + JsonObject vertexObject = champObject.get("vertex").getAsJsonObject(); + Vertex vertex = OxmModelValidator.validateOutgoingPayload(version, buildVertex(vertexObject)); + this.getVertices().put(itemKey, vertex); + } + + for (JsonElement rel : this.getRelationships()) { + + JsonObject champRelationship = rel.getAsJsonObject(); + String itemKey = champRelationship.get("label").getAsString(); + JsonObject relObject = champRelationship.get("edge").getAsJsonObject(); + Edge edge = RelationshipSchemaValidator.validateOutgoingPayload(version, buildEdge(relObject)); + this.getEdges().put(itemKey, edge); + + } + + + } + + + private Edge buildEdge(JsonObject obj) { + JsonObject relKeyObject = obj.get("key").getAsJsonObject(); + + String relType = obj.get("type").getAsString(); + String relKey = relKeyObject.get("value").getAsString(); + + Vertex source = buildVertex(obj.get("source").getAsJsonObject()); + Vertex target = buildVertex(obj.get("target").getAsJsonObject()); + + Edge.Builder edgeBuilder = new Edge.Builder(relType).id(relKey).source(source) + .target(target); + + if (obj.has("properties")) { + JsonObject propsObject = obj.get("properties").getAsJsonObject(); + List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>( + propsObject.getAsJsonObject().entrySet()); + + for (Map.Entry<String, JsonElement> entry :entries) { + edgeBuilder.property(entry.getKey(), entry.getValue().getAsString()); + } + + } + + return edgeBuilder.build(); + } + + private Vertex buildVertex(JsonObject obj) { + JsonObject vertexKeyObject = obj.get("key").getAsJsonObject(); + + String vertexType = obj.get("type").getAsString(); + String vertexKey = vertexKeyObject.get("value").getAsString(); + Vertex.Builder vertexBuilder = new Vertex.Builder(vertexType).id(vertexKey); + + if (obj.has("properties")) { + JsonObject propsObject = obj.get("properties").getAsJsonObject(); + List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>( + propsObject.getAsJsonObject().entrySet()); + + for (Map.Entry<String, JsonElement> entry :entries) { + vertexBuilder.property(entry.getKey(), entry.getValue().getAsString()); + } + + } + + return vertexBuilder.build(); + } + + public HashMap<String, Edge> getEdges() { + return edges; + } + + public void setEdges(HashMap<String, Edge> edges) { + this.edges = edges; + } + + public List<JsonElement> getObjects() { + return objects; + } + + public void setObjects(List<JsonElement> objects) { + this.objects = objects; + } + + public HashMap<String, Vertex> getVertices() { + return vertices; + } + + public List<JsonElement> getRelationships() { + return relationships; + } + + + + +} diff --git a/src/main/java/org/onap/crud/dao/champ/ChampDao.java b/src/main/java/org/onap/crud/dao/champ/ChampDao.java index 554b9fa..402d2cf 100644 --- a/src/main/java/org/onap/crud/dao/champ/ChampDao.java +++ b/src/main/java/org/onap/crud/dao/champ/ChampDao.java @@ -54,6 +54,7 @@ public class ChampDao implements GraphDao { protected String baseObjectUrl; protected String baseRelationshipUrl; protected String baseTransactionUrl; + protected String baseBulkUrl; protected static final String HEADER_FROM_APP = "X-FromAppId"; protected static final String HEADER_TRANS_ID = "X-TransactionId"; @@ -61,13 +62,14 @@ public class ChampDao implements GraphDao { protected static final String OBJECT_SUB_URL = "objects"; protected static final String RELATIONSHIP_SUB_URL = "relationships"; protected static final String TRANSACTION_SUB_URL = "transaction"; + protected static final String BULK_SUB_URL = "bulk"; // We use a custom vertex serializer for champ because it expects "key" // instead of "id" protected static final Gson champGson = new GsonBuilder() - .registerTypeAdapterFactory(new GsonJava8TypeAdapterFactory()) - .registerTypeAdapter(Vertex.class, new ChampVertexSerializer()) - .registerTypeAdapter(Edge.class, new ChampEdgeSerializer()).create(); + .registerTypeAdapterFactory(new GsonJava8TypeAdapterFactory()) + .registerTypeAdapter(Vertex.class, new ChampVertexSerializer()) + .registerTypeAdapter(Edge.class, new ChampEdgeSerializer()).create(); public ChampDao() { } @@ -76,12 +78,13 @@ public class ChampDao implements GraphDao { try { String deobfuscatedCertPassword = certPassword.startsWith("OBF:")?Password.deobfuscate(certPassword):certPassword; client = new RestClient().authenticationMode(RestAuthenticationMode.SSL_CERT).validateServerHostname(false) - .validateServerCertChain(false).clientCertFile(CrudServiceConstants.CRD_CHAMP_AUTH_FILE) - .clientCertPassword(deobfuscatedCertPassword); + .validateServerCertChain(false).clientCertFile(CrudServiceConstants.CRD_CHAMP_AUTH_FILE) + .clientCertPassword(deobfuscatedCertPassword); baseObjectUrl = champUrl + OBJECT_SUB_URL; baseRelationshipUrl = champUrl + RELATIONSHIP_SUB_URL; baseTransactionUrl = champUrl + TRANSACTION_SUB_URL; + baseBulkUrl = champUrl + BULK_SUB_URL; } catch (Exception e) { System.out.println("Error setting up Champ configuration"); e.printStackTrace(); @@ -90,10 +93,10 @@ public class ChampDao implements GraphDao { } public ChampDao(RestClient client, String baseObjectUrl, String baseRelationshipUrl, String baseTransactionUrl) { - this.client = client; - this.baseObjectUrl = baseObjectUrl; - this.baseRelationshipUrl = baseRelationshipUrl; - this.baseTransactionUrl = baseTransactionUrl; + this.client = client; + this.baseObjectUrl = baseObjectUrl; + this.baseRelationshipUrl = baseRelationshipUrl; + this.baseTransactionUrl = baseTransactionUrl; } @Override @@ -117,8 +120,8 @@ public class ChampDao implements GraphDao { strBuild.append(id); if(queryParams != null && !queryParams.isEmpty()) { - strBuild.append("?"); - strBuild.append(URLEncodedUtils.format(convertToNameValuePair(queryParams), Charset.defaultCharset())); + strBuild.append("?"); + strBuild.append(URLEncodedUtils.format(convertToNameValuePair(queryParams), Charset.defaultCharset())); } OperationResult getResult = client.get(strBuild.toString(), createHeader(), MediaType.APPLICATION_JSON_TYPE); @@ -130,50 +133,50 @@ public class ChampDao implements GraphDao { // We didn't find a vertex with the supplied type, so just throw an // exception. throw new CrudException("No vertex with id " + id + " and type " + type + " found in graph", - javax.ws.rs.core.Response.Status.NOT_FOUND); + javax.ws.rs.core.Response.Status.NOT_FOUND); } return getResult; } else { // We didn't find a vertex with the supplied id, so just throw an // exception. - throw createErrorException(getResult, javax.ws.rs.core.Response.Status.NOT_FOUND, "No vertex with id " + id + " found in graph"); + throw createErrorException(getResult, javax.ws.rs.core.Response.Status.NOT_FOUND, "No vertex with id " + id + " found in graph"); } } @Override public List<Edge> getVertexEdges(String id, Map<String, String> queryParams, String txId) throws CrudException { - StringBuilder strBuild = new StringBuilder(baseObjectUrl); - strBuild.append("/relationships/"); - strBuild.append(id); + StringBuilder strBuild = new StringBuilder(baseObjectUrl); + strBuild.append("/relationships/"); + strBuild.append(id); - Map<String,String> queryParamsCopy = null; - if (queryParams != null) { - queryParamsCopy = new HashMap<String,String>(queryParams); - } - else { - queryParamsCopy = new HashMap<String,String>(); - } + Map<String,String> queryParamsCopy = null; + if (queryParams != null) { + queryParamsCopy = new HashMap<String,String>(queryParams); + } + else { + queryParamsCopy = new HashMap<String,String>(); + } - if (txId != null) { - queryParamsCopy.put("transactionId", txId); - } + if (txId != null) { + queryParamsCopy.put("transactionId", txId); + } - if (!queryParamsCopy.isEmpty()) - { - strBuild.append("?"); - strBuild.append(URLEncodedUtils.format(convertToNameValuePair(queryParamsCopy), Charset.defaultCharset())); - } + if (!queryParamsCopy.isEmpty()) + { + strBuild.append("?"); + strBuild.append(URLEncodedUtils.format(convertToNameValuePair(queryParamsCopy), Charset.defaultCharset())); + } - OperationResult getResult = client.get(strBuild.toString(), createHeader(), MediaType.APPLICATION_JSON_TYPE); + OperationResult getResult = client.get(strBuild.toString(), createHeader(), MediaType.APPLICATION_JSON_TYPE); - if (getResult.getResultCode() == 200) { - return champGson.fromJson(getResult.getResult(), new TypeToken<List<Edge>>() { - }.getType()); - } else { - // We didn't find a vertex with the supplied id, so just throw an - // exception. - throw createErrorException(getResult, javax.ws.rs.core.Response.Status.NOT_FOUND, "No vertex with id " + id + " found in graph"); - } + if (getResult.getResultCode() == 200) { + return champGson.fromJson(getResult.getResult(), new TypeToken<List<Edge>>() { + }.getType()); + } else { + // We didn't find a vertex with the supplied id, so just throw an + // exception. + throw createErrorException(getResult, javax.ws.rs.core.Response.Status.NOT_FOUND, "No vertex with id " + id + " found in graph"); + } } @Override @@ -188,7 +191,7 @@ public class ChampDao implements GraphDao { List<NameValuePair> queryParams = convertToNameValuePair(filter); queryParams.addAll(convertToNameValuePair("properties", properties)); String url = baseObjectUrl + "/filter" + "?" - + URLEncodedUtils.format(queryParams, Charset.defaultCharset()); + + URLEncodedUtils.format(queryParams, Charset.defaultCharset()); OperationResult getResult = client.get(url, createHeader(), MediaType.APPLICATION_JSON_TYPE); @@ -208,8 +211,8 @@ public class ChampDao implements GraphDao { strBuild.append(id); if(queryParams != null && !queryParams.isEmpty()) { - strBuild.append("?"); - strBuild.append(URLEncodedUtils.format(convertToNameValuePair(queryParams), Charset.defaultCharset())); + strBuild.append("?"); + strBuild.append(URLEncodedUtils.format(convertToNameValuePair(queryParams), Charset.defaultCharset())); } OperationResult getResult = client.get(strBuild.toString(), createHeader(), MediaType.APPLICATION_JSON_TYPE); @@ -220,7 +223,7 @@ public class ChampDao implements GraphDao { // We didn't find an edge with the supplied type, so just throw an // exception. throw new CrudException("No edge with id " + id + " and type " + type + " found in graph", - javax.ws.rs.core.Response.Status.NOT_FOUND); + javax.ws.rs.core.Response.Status.NOT_FOUND); } return getResult; } else { @@ -233,12 +236,12 @@ public class ChampDao implements GraphDao { @Override public OperationResult getEdges(String type, Map<String, Object> filter) throws CrudException { String url = baseRelationshipUrl + "/filter" + "?" - + URLEncodedUtils.format(convertToNameValuePair(filter), Charset.defaultCharset()); + + URLEncodedUtils.format(convertToNameValuePair(filter), Charset.defaultCharset()); OperationResult getResult = client.get(url, createHeader(), MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == 200) { - return getResult; + return getResult; } else { // We didn't find a vertex with the supplied id, so just throw an // exception. @@ -259,7 +262,7 @@ public class ChampDao implements GraphDao { Vertex insertVertex = insertVertexBuilder.build(); OperationResult getResult = client.post(url, insertVertex.toJson(), createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) { return getResult; @@ -285,7 +288,7 @@ public class ChampDao implements GraphDao { String payload = insertVertex.toJson(champGson); OperationResult getResult = client.put(url, payload, createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) { return getResult; @@ -324,7 +327,7 @@ public class ChampDao implements GraphDao { String edgeJson = insertEdge.toJson(champGson); OperationResult getResult = client.post(url, edgeJson, createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) { return getResult; @@ -344,7 +347,7 @@ public class ChampDao implements GraphDao { String edgeJson = edge.toJson(champGson); OperationResult getResult = client.put(url, edgeJson, createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) { return getResult; @@ -385,11 +388,11 @@ public class ChampDao implements GraphDao { String url = baseTransactionUrl + "/" + id; OperationResult getResult = client.put(url, "{\"method\": \"commit\"}", createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.TEXT_PLAIN_TYPE); + MediaType.TEXT_PLAIN_TYPE); if (getResult.getResultCode() != 200) { throw new CrudException("Unable to commit transaction", - Response.Status.fromStatusCode(getResult.getResultCode())); + Response.Status.fromStatusCode(getResult.getResultCode())); } } @@ -398,11 +401,11 @@ public class ChampDao implements GraphDao { String url = baseTransactionUrl + "/" + id; OperationResult getResult = client.put(url, "{\"method\": \"rollback\"}", createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.TEXT_PLAIN_TYPE); + MediaType.TEXT_PLAIN_TYPE); if (getResult.getResultCode() != 200) { throw new CrudException("Unable to rollback transaction", - Response.Status.fromStatusCode(getResult.getResultCode())); + Response.Status.fromStatusCode(getResult.getResultCode())); } } @@ -431,7 +434,7 @@ public class ChampDao implements GraphDao { Vertex insertVertex = insertVertexBuilder.build(); OperationResult getResult = client.post(url, insertVertex.toJson(), createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) { return Vertex.fromJson(getResult.getResult(), version); @@ -444,7 +447,7 @@ public class ChampDao implements GraphDao { @Override public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties, String version, String txId) - throws CrudException { + throws CrudException { String url = baseRelationshipUrl + "?transactionId=" + txId; // Try requests to ensure source and target exist in Champ @@ -456,7 +459,7 @@ public class ChampDao implements GraphDao { Edge insertEdge = insertEdgeBuilder.build(); OperationResult getResult = client.post(url, insertEdge.toJson(champGson), createHeader(), - MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) { return Edge.fromJson(getResult.getResult()); @@ -482,7 +485,7 @@ public class ChampDao implements GraphDao { String payload = insertVertex.toJson(champGson); OperationResult getResult = client.put(url, payload, createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) { return Vertex.fromJson(getResult.getResult(), version); @@ -512,7 +515,7 @@ public class ChampDao implements GraphDao { } String url = baseRelationshipUrl + "/" + edge.getId().get() + "?transactionId=" + txId; OperationResult getResult = client.put(url, edge.toJson(champGson), createHeader(), MediaType.APPLICATION_JSON_TYPE, - MediaType.APPLICATION_JSON_TYPE); + MediaType.APPLICATION_JSON_TYPE); if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) { return Edge.fromJson(getResult.getResult()); @@ -520,7 +523,7 @@ public class ChampDao implements GraphDao { // We didn't create an edge with the supplied type, so just throw an // exception. throw new CrudException("Failed to update edge: " + getResult.getFailureCause(), - Response.Status.fromStatusCode(getResult.getResultCode())); + Response.Status.fromStatusCode(getResult.getResultCode())); } } @@ -576,7 +579,7 @@ public class ChampDao implements GraphDao { // We didn't find a vertex with the supplied type, so just throw an // exception. throw new CrudException("No vertex with id " + id + " and type " + type + " found in graph", - javax.ws.rs.core.Response.Status.NOT_FOUND); + javax.ws.rs.core.Response.Status.NOT_FOUND); } return vert; } else { @@ -613,12 +616,26 @@ public class ChampDao implements GraphDao { private CrudException createErrorException(OperationResult result, javax.ws.rs.core.Response.Status defaultErrorCode , String defaultErrorMsg) { - CrudException ce = null; - if(result != null) - ce = new CrudException(result.getFailureCause(), Response.Status.fromStatusCode(result.getResultCode())); - else - ce = new CrudException(defaultErrorMsg, defaultErrorCode); - return ce; + CrudException ce = null; + if(result != null) + ce = new CrudException(result.getFailureCause(), Response.Status.fromStatusCode(result.getResultCode())); + else + ce = new CrudException(defaultErrorMsg, defaultErrorCode); + return ce; + } + + @Override + public OperationResult bulkOperation(ChampBulkPayload champPayload) throws CrudException { + String url = baseBulkUrl; + + OperationResult getResult = client.post(url, champPayload.toJson(), createHeader(), MediaType.APPLICATION_JSON_TYPE, + MediaType.APPLICATION_JSON_TYPE); + + if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) { + return getResult; + } else { + throw new CrudException("Bulk request failed: " + getResult.getFailureCause(), Response.Status.fromStatusCode(getResult.getResultCode())); + } } } |