summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/onap/crud
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/onap/crud')
-rw-r--r--src/main/java/org/onap/crud/dao/GraphDao.java183
-rw-r--r--src/main/java/org/onap/crud/dao/champ/ChampDao.java883
-rw-r--r--src/main/java/org/onap/crud/dao/champion/ChampionDao.java623
-rw-r--r--src/main/java/org/onap/crud/dao/champion/ChampionEdgeSerializer.java49
-rw-r--r--src/main/java/org/onap/crud/dao/champion/ChampionVertexSerializer.java47
-rw-r--r--src/main/java/org/onap/crud/entity/Edge.java140
-rw-r--r--src/main/java/org/onap/crud/entity/Vertex.java115
-rw-r--r--src/main/java/org/onap/crud/event/GraphEvent.java235
-rw-r--r--src/main/java/org/onap/crud/event/GraphEventEdge.java212
-rw-r--r--src/main/java/org/onap/crud/event/GraphEventVertex.java181
-rw-r--r--src/main/java/org/onap/crud/exception/CrudException.java62
-rw-r--r--src/main/java/org/onap/crud/logging/CrudServiceMsgs.java87
-rw-r--r--src/main/java/org/onap/crud/logging/LoggingUtil.java82
-rw-r--r--src/main/java/org/onap/crud/parser/CrudResponseBuilder.java212
-rw-r--r--src/main/java/org/onap/crud/service/AaiResourceService.java533
-rw-r--r--src/main/java/org/onap/crud/service/BulkPayload.java124
-rw-r--r--src/main/java/org/onap/crud/service/CrudGraphDataService.java301
-rw-r--r--src/main/java/org/onap/crud/service/CrudRestService.java784
-rw-r--r--src/main/java/org/onap/crud/service/EdgePayload.java115
-rw-r--r--src/main/java/org/onap/crud/service/JaxrsEchoService.java63
-rw-r--r--src/main/java/org/onap/crud/service/VertexPayload.java117
-rw-r--r--src/main/java/org/onap/crud/util/CrudJaxbTransformation.java92
-rw-r--r--src/main/java/org/onap/crud/util/CrudProperties.java77
-rw-r--r--src/main/java/org/onap/crud/util/CrudServiceConstants.java54
-rw-r--r--src/main/java/org/onap/crud/util/CrudServiceUtil.java63
-rw-r--r--src/main/java/org/onap/crud/util/FileWatcher.java48
26 files changed, 5482 insertions, 0 deletions
diff --git a/src/main/java/org/onap/crud/dao/GraphDao.java b/src/main/java/org/onap/crud/dao/GraphDao.java
new file mode 100644
index 0000000..bc42b15
--- /dev/null
+++ b/src/main/java/org/onap/crud/dao/GraphDao.java
@@ -0,0 +1,183 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.dao;
+
+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;
+
+public interface GraphDao {
+
+ public Vertex getVertex(String id) throws CrudException;
+
+ public Vertex getVertex(String id, String type) throws CrudException;
+
+ /**
+ * Retrieve all of the edges which are incident to the vertex with the
+ * specified identifier.
+ *
+ * @param id
+ * - The unique identifier of the vertex to retrieve the edges for.
+ * @return - A collection of edges.
+ * @throws CrudException
+ */
+ public List<Edge> getVertexEdges(String id) throws CrudException;
+
+ /**
+ * Retrieve a collection of {@link Vertex} objects which match the supplied
+ * type label and filter properties.
+ *
+ * @param type
+ * - The vertex type that we want to retrieve.
+ * @param filter
+ * - The parameters to filter our results by.
+ * @return - A collection of vertices.
+ * @throws CrudException
+ */
+ public List<Vertex> getVertices(String type, Map<String, Object> filter) throws CrudException;
+
+ /**
+ * Retrieve an {@link Edge} from the graph database by specifying its unique
+ * identifier.
+ *
+ * @param id
+ * - The unique identifier for the Edge to be retrieved.
+ * @return - The Edge corresponding to the specified identifier.
+ * @throws CrudException
+ */
+ public Edge getEdge(String id, String type) throws CrudException;
+
+ /**
+ * Retrieve a collection of {@link Edge} objects with a given type and which
+ * match a set of supplied filter parameters.
+ *
+ * @param type
+ * - The type of edges that we are interested in.
+ * @param filter
+ * - The parameters that we want to filter our edges by.
+ * @return - A collection of edges which match the supplied filter parameters.
+ * @throws CrudException
+ */
+ public List<Edge> getEdges(String type, Map<String, Object> filter) throws CrudException;
+
+ /**
+ * Insert a new {@link Vertex} into the graph data store.
+ *
+ * @param type
+ * - The type label to assign to the vertex.
+ * @param properties
+ * - The properties to associated with this vertex.
+ * @return - The {@link Vertex} object that was created.
+ * @throws CrudException
+ */
+ public Vertex addVertex(String type, Map<String, Object> properties) throws CrudException;
+
+ /**
+ * Updates an existing {@link Vertex}.
+ *
+ * @param id
+ * - The unique identifier of the vertex to be updated.
+ * @param properties
+ * - The properties to associate with the vertex.
+ * @return - The udpated vertex.
+ * @throws CrudException
+ */
+ public Vertex updateVertex(String id, String type, Map<String, Object> properties) throws CrudException;
+
+ /**
+ * Removes the specified vertex from the graph data base.
+ *
+ * <p>
+ * NOTE: The vertex MUST contain NO incident edges before it can be deleted.
+ *
+ * @param id
+ * - The unique identifier of the vertex to be deleted.
+ * @throws CrudException
+ */
+ public void deleteVertex(String id, String type) throws CrudException;
+
+ /**
+ * Adds an edge to the graph database.
+ *
+ * @param type
+ * - The 'type' label to apply to the edge.
+ * @param source
+ * - The source vertex for this edge.
+ * @param target
+ * - The target vertex for this edge.
+ * @param properties
+ * - The properties map to associate with this edge.
+ * @return - The {@link Edge} object that was created.
+ * @throws CrudException
+ */
+ public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties) throws CrudException;
+
+ /**
+ * Updates an existing {@link Edge}.
+ *
+ * @param id
+ * - The unique identifier of the edge to be updated.
+ * @param properties
+ * - The properties to associate with the edge.
+ * @return - The update edge.
+ * @throws CrudException
+ */
+ public Edge updateEdge(Edge edge) throws CrudException;
+
+ /**
+ * Remove the specified edge from the graph data base.
+ *
+ * @param id
+ * - The unique identifier of the edge to be deleted.
+ * @throws CrudException
+ */
+ public void deleteEdge(String id, String type) throws CrudException;
+
+ public String openTransaction();
+
+ public void commitTransaction(String id) throws CrudException;
+
+ public void rollbackTransaction(String id) throws CrudException;
+
+ public boolean transactionExists(String id) throws CrudException;
+
+ public Vertex addVertex(String type, Map<String, Object> properties, String txId) throws CrudException;
+
+ public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties, String txId)
+ throws CrudException;
+
+ public Vertex updateVertex(String id, String type, Map<String, Object> properties, String txId) throws CrudException;
+
+ public Edge updateEdge(Edge edge, String txId) throws CrudException;
+
+ public void deleteVertex(String id, String type, String txId) throws CrudException;
+
+ public void deleteEdge(String id, String type, String txId) throws CrudException;
+
+ public Edge getEdge(String id, String type, String txId) throws CrudException;
+}
diff --git a/src/main/java/org/onap/crud/dao/champ/ChampDao.java b/src/main/java/org/onap/crud/dao/champ/ChampDao.java
new file mode 100644
index 0000000..f217897
--- /dev/null
+++ b/src/main/java/org/onap/crud/dao/champ/ChampDao.java
@@ -0,0 +1,883 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.dao.champ;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.aai.champcore.ChampTransaction;
+import org.onap.aai.champcore.exceptions.ChampMarshallingException;
+import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
+import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
+import org.onap.aai.champcore.exceptions.ChampTransactionException;
+import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
+import org.onap.aai.champcore.model.ChampObject;
+import org.onap.aai.champcore.model.ChampRelationship;
+import org.onap.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+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.logging.CrudServiceMsgs;
+
+/**
+ * This is the integration layer between the CRUD API service and the low level
+ * Champ library for graph database interaction.
+ */
+public class ChampDao implements GraphDao {
+
+ public static final String CONFIG_STORAGE_BACKEND = "storage.backend";
+ public static final String CONFIG_STORAGE_BACKEND_DB = "storage.backend.db";
+ public static final String STORAGE_HBASE_DB = "hbase";
+ public static final String STORAGE_CASSANDRA_DB = "cassandra";
+ public static final String CONFIG_STORAGE_HOSTNAMES = "storage.hostnames";
+ public static final String CONFIG_STORAGE_PORT = "storage.port";
+ public static final String CONFIG_HBASE_ZNODE_PARENT = "storage.hbase.ext.zookeeper.znode.parent";
+ public static final String CONFIG_GRAPH_NAME = "graph.name";
+ public static final String GRAPH_UNQ_INSTANCE_ID_SUFFIX = "graph.unique-instance-id-suffix";
+
+ public static final String CONFIG_EVENT_STREAM_PUBLISHER = "event.stream.publisher";
+ public static final String CONFIG_EVENT_STREAM_NUM_PUBLISHERS = "event.stream.num-publishers";
+
+ private static Map<String, ChampTransaction> transactions = new ConcurrentHashMap<String, ChampTransaction>();
+ public static final String DEFAULT_GRAPH_NAME = "default_graph";
+
+ private enum GraphType {
+ IN_MEMORY, TITAN, DSE
+ }
+
+ /**
+ * Instance of the API used for interacting with the Champ library.
+ */
+ private ChampGraph champApi = null;
+
+ private Logger logger = LoggerFactory.getInstance().getLogger(ChampDao.class.getName());
+
+ /**
+ * Creates a new instance of the ChampDao.
+ *
+ * @param champGraph
+ * - Concrete implementation of the graph dao layer
+ */
+ public ChampDao(ChampGraph champGraph) {
+ this.champApi = champGraph;
+ }
+
+ @Override
+ public Vertex getVertex(String id) throws CrudException {
+
+ try {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("getVertex with id: " + id);
+ }
+
+ long idAsLong = Long.parseLong(id);
+
+ Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
+
+ String nodeType = org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName();
+ if (retrievedVertex.isPresent() && retrievedVertex.get().getProperties().get(nodeType) != null) {
+ return vertexFromChampObject(retrievedVertex.get(),
+ retrievedVertex.get().getProperties().get(nodeType).toString());
+ } else {
+
+ // We didn't find a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ } catch (ChampUnmarshallingException | ChampTransactionException e) {
+
+ // Something went wrong - throw an exception.
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public Vertex getVertex(String id, String type) throws CrudException {
+
+ try {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("getVertex with id: " + id);
+ }
+
+ long idAsLong = Long.parseLong(id);
+
+ // Request the vertex from the graph db.
+ Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
+
+ // Did we find it?
+ if (retrievedVertex.isPresent()
+ && retrievedVertex.get().getProperties()
+ .get(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) != null
+ && retrievedVertex.get().getProperties()
+ .get(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()
+ .equalsIgnoreCase(type)) {
+
+ // Yup, convert it to a Vector object and return it.
+ return vertexFromChampObject(retrievedVertex.get(), type);
+
+ } else {
+
+ // We didn't find a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ } catch (ChampUnmarshallingException | ChampTransactionException e) {
+
+ // Something went wrong - throw an exception.
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public List<Edge> getVertexEdges(String id) throws CrudException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("get Edges incident to vertex with id: " + id + " from graph");
+ }
+
+ try {
+ long idAsLong = Long.parseLong(id); // GDF - what to do about id???
+
+ // Request the vertex from the graph db.
+ Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
+
+ // Did we find it?
+ if (retrievedVertex.isPresent()) {
+
+ // Query the Champ library for the edges which are incident to the
+ // specified
+ // vertex.
+ Stream<ChampRelationship> relationships = champApi.retrieveRelationships(retrievedVertex.get());
+
+ // Build an edge list from the result stream.
+ List<Edge> edges = new ArrayList<Edge>();
+ relationships.forEach(r -> edges.add(edgeFromChampRelationship(r)));
+
+ return edges;
+
+ } else {
+
+ // We couldn't find the specified vertex, so throw an exception.
+ throw new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ } catch (ChampUnmarshallingException e) {
+
+ // Something went wrong, so throw an exception.
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+
+ } catch (ChampObjectNotExistsException e) {
+
+ // We couldn't find the specified vertex, so throw an exception.
+ throw new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ } catch (ChampTransactionException e) {
+ throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public Vertex addVertex(String type, Map<String, Object> properties) throws CrudException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Add/update vertex: {label: " + type + " properties:" + propertiesMapToString(properties));
+ }
+
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ // Create an object to represent our vertex in the format expected by the
+ // Champ library.
+ ChampObject objectToCreate = buildChampObject(type, properties);
+
+ try {
+
+ // Ask the Champ library to store our vertex, placing the returned object
+ // into a
+ // list so that we can easily put that into our result object.
+ return vertexFromChampObject(champApi.storeObject(objectToCreate), type);
+
+ } catch (ChampMarshallingException | ChampSchemaViolationException | ChampObjectNotExistsException
+ | ChampTransactionException e) {
+
+ // Something went wrong - throw an exception.
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public Vertex updateVertex(String id, String type, Map<String, Object> properties) throws CrudException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Update vertex with id: " + id + " with properties: " + propertiesMapToString(properties));
+ }
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ try {
+ // Now, build the updated version of the Champ Object...
+ ChampObject updateObject = buildChampObject(id, type, properties);
+ // ...and send it to the Champ library.
+ return vertexFromChampObject(champApi.replaceObject(updateObject), type);
+
+ } catch (ChampObjectNotExistsException e) {
+ throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ } catch (NumberFormatException | ChampMarshallingException | ChampSchemaViolationException e) {
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (ChampTransactionException e) {
+ throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ }
+
+ @Override
+ public List<Vertex> getVertices(String type, Map<String, Object> filter) throws CrudException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Retrieve vertices with type label: " + type + " which map query parameters: "
+ + propertiesMapToString(filter));
+ }
+
+ filter.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ Stream<ChampObject> retrievedVertices;
+ try {
+ retrievedVertices = champApi.queryObjects(filter);
+
+ } catch (ChampTransactionException e) {
+ throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ List<Vertex> vertices = retrievedVertices.map(v -> vertexFromChampObject(v, type)).collect(Collectors.toList());
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Resulting vertex list: " + retrievedVertices);
+ }
+
+ // ...and return it to the caller.
+ return vertices;
+ }
+
+ private Object getRelKey(String id) {
+ Object key = id;
+ // convert into Long if applicable . TODO : revisit in story NUC-304
+ try {
+ key = Long.parseLong(id);
+ } catch (NumberFormatException e) {
+ // The id isn't a Long, leave it as a string
+ }
+
+ return key;
+ }
+
+ @Override
+ public Edge getEdge(String id, String type) throws CrudException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Get edge with id: " + id);
+ }
+
+ try {
+
+ // Request the edge from the graph db.
+ Optional<ChampRelationship> relationship = champApi.retrieveRelationship(getRelKey(id));
+
+ // Did we find it?
+ if (relationship.isPresent() && relationship.get().getType().equals(type)) {
+
+ // Yup - return the result.
+ return edgeFromChampRelationship(relationship.get());
+
+ } else {
+
+ // We didn't find an edge with the supplied id, so throw an exception.
+ throw new CrudException("No edge with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ } catch (ChampUnmarshallingException | ChampTransactionException e) {
+
+ // Something went wrong, so throw an exception.
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties) throws CrudException {
+
+ // For now, assume source and target are straight ids...
+ try {
+
+ Optional<ChampObject> sourceObject = champApi.retrieveObject(Long.parseLong(source.getId().get()));
+ if (!sourceObject.isPresent() || !sourceObject.get().getType().equals(source.getType())) {
+ throw new CrudException(
+ "Error creating edge - source vertex with id " + source + " does not exist in graph data base",
+ javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ }
+
+ Optional<ChampObject> targetObject = champApi.retrieveObject(Long.parseLong(target.getId().get()));
+ if (!targetObject.isPresent() || !targetObject.get().getType().equals(target.getType())) {
+ throw new CrudException(
+ "Error creating edge - target vertex with id " + target + " does not exist in graph data base",
+ javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ }
+
+ // Now, create the ChampRelationship object for our edge and store it in
+ // the graph database.
+ return edgeFromChampRelationship(champApi.storeRelationship(
+ new ChampRelationship.Builder(sourceObject.get(), targetObject.get(), type).properties(properties).build()));
+
+ } catch (ChampMarshallingException | ChampObjectNotExistsException | ChampSchemaViolationException
+ | ChampRelationshipNotExistsException | ChampUnmarshallingException | NumberFormatException
+ | ChampTransactionException e) {
+
+ throw new CrudException("Error creating edge: " + e.getMessage(),
+ javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public List<Edge> getEdges(String type, Map<String, Object> filter) throws CrudException {
+
+ filter.put(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString(), type);
+
+ Stream<ChampRelationship> retrievedRelationships;
+ try {
+ retrievedRelationships = champApi.queryRelationships(filter);
+
+ } catch (ChampTransactionException e) {
+ throw new CrudException("Transaction error occured", javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ // Process the result stream from the Champ library into an Edge list,
+ // keeping only
+ // edges of the specified type.
+ List<Edge> edges = retrievedRelationships.map(r -> edgeFromChampRelationship(r)).collect(Collectors.toList());
+
+ return edges;
+ }
+
+ @Override
+ public Edge updateEdge(Edge edge) throws CrudException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "Update edge with id: " + edge.getId() + " with properties: " + propertiesMapToString(edge.getProperties()));
+ }
+
+ try {
+ // Now, build the updated version of the Champ Relationship...
+ ChampRelationship updateRelationship = new ChampRelationship.Builder(
+ buildChampObject(edge.getSource().getId().get(), edge.getSource().getType(),
+ edge.getSource().getProperties()),
+ buildChampObject(edge.getTarget().getId().get(), edge.getTarget().getType(),
+ edge.getTarget().getProperties()),
+ edge.getType()).key(getRelKey(edge.getId().get())).properties(edge.getProperties()).build();
+ // ...and send it to the Champ library.
+ return edgeFromChampRelationship(champApi.replaceRelationship(updateRelationship));
+
+ } catch (ChampRelationshipNotExistsException ex) {
+ throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ } catch (NumberFormatException | ChampUnmarshallingException | ChampMarshallingException
+ | ChampSchemaViolationException | ChampTransactionException ex) {
+
+ throw new CrudException(ex.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public void deleteVertex(String id, String type) throws CrudException {
+
+ try {
+
+ // First, retrieve the vertex that we intend to delete.
+ Optional<ChampObject> retrievedVertex = champApi.retrieveObject(Long.parseLong(id));
+
+ // Did we find it?
+ if (!retrievedVertex.isPresent() || !retrievedVertex.get().getType().equals(type)) {
+ throw new CrudException("Failed to delete vertex with id: " + id + " - vertex does not exist.",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ // Now, verify that there are no edges incident to the vertex (they must
+ // be deleted
+ // first if so).
+ Stream<ChampRelationship> relationships = champApi.retrieveRelationships(retrievedVertex.get());
+
+ if (relationships.count() > 0) {
+ throw new CrudException("Attempt to delete vertex with id " + id + " which has incident edges.",
+ javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ }
+
+ // Finally, we can attempt to delete our vertex.
+ champApi.deleteObject(Long.parseLong(id));
+
+ } catch (NumberFormatException | ChampUnmarshallingException | ChampObjectNotExistsException
+ | ChampTransactionException e) {
+
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public void deleteEdge(String id, String type) throws CrudException {
+
+ try {
+
+ // First, retrieve the edge that we want to delete.
+ Optional<ChampRelationship> relationshipToDelete = champApi.retrieveRelationship(getRelKey(id));
+
+ // Did we find it?
+ if (!relationshipToDelete.isPresent() || !relationshipToDelete.get().getType().equals(type)) {
+ throw new CrudException("Failed to delete edge with id: " + id + " - edge does not exist",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ // Now we can delete the edge.
+ champApi.deleteRelationship(relationshipToDelete.get());
+
+ } catch (ChampRelationshipNotExistsException | NumberFormatException | ChampUnmarshallingException
+ | ChampTransactionException e) {
+
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * This helper method generates a string representation of a properties map
+ * for logging purposes.
+ *
+ * @param properties
+ * - The properties map to be converted.
+ * @return - The log statement friendly conversion of the properties map.
+ */
+ private String propertiesMapToString(Map<String, Object> properties) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("{");
+
+ for (String key : properties.keySet()) {
+ sb.append("(").append(key).append(" -> ").append(properties.get(key)).append(") ");
+ }
+
+ sb.append("}");
+
+ return sb.toString();
+ }
+
+ /**
+ * This helper method constructs a {@link ChampObject} suitable for passing to
+ * the Champ library.
+ *
+ * @param type
+ * - The type to assign to our ChampObject
+ * @param properties
+ * - The set of properties to assign to our ChampObject
+ * @return - A populated ChampObject
+ */
+ private ChampObject buildChampObject(String type, Map<String, Object> properties) {
+
+ ObjectBuildOrPropertiesStep objectInProgress = ChampObject.create().ofType(type).withoutKey();
+
+ for (String key : properties.keySet()) {
+ objectInProgress.withProperty(key, properties.get(key));
+ }
+ return objectInProgress.build();
+ }
+
+ /**
+ * This helper method constructs a {@link ChampObject} suitable for passing to
+ * the Champ library.
+ *
+ * @param id
+ * - Unique identifier for this object.
+ * @param type
+ * - The type to assign to our ChampObject
+ * @param properties
+ * - The set of properties to assign to our ChampObject
+ * @return - A populated ChampObject
+ */
+ private ChampObject buildChampObject(String id, String type, Map<String, Object> properties) {
+
+ ObjectBuildOrPropertiesStep objectInProgress = ChampObject.create().ofType(type).withKey(Long.parseLong(id));
+
+ for (String key : properties.keySet()) {
+ objectInProgress.withProperty(key, properties.get(key));
+ }
+ return objectInProgress.build();
+ }
+
+ private Vertex vertexFromChampObject(ChampObject champObject, String type) {
+
+ // Get the identifier for this vertex from the Champ object.
+ Object id = champObject.getKey().orElse("");
+
+ // Start building our {@link Vertex} object.
+ Vertex.Builder vertexBuilder = new Vertex.Builder(type);
+ vertexBuilder.id(id.toString());
+
+ // Convert the properties associated with the Champ object into the form
+ // expected for
+ // a Vertex object.
+ for (String key : champObject.getProperties().keySet()) {
+ vertexBuilder.property(key, champObject.getProperties().get(key));
+ }
+
+ // ...and return it.
+ return vertexBuilder.build();
+ }
+
+ /**
+ * This helper method converts a {@link ChampRelationship} from the Champ
+ * library into an equivalent {@link Edge} object that is understood by the
+ * CRUD Service.
+ *
+ * @param relationship
+ * - The ChampRelationship object to be converted.
+ * @return - An Edge object corresponding to the supplied ChampRelationship
+ */
+ private Edge edgeFromChampRelationship(ChampRelationship relationship) {
+
+ // Populate the edge's id, if available.
+ Object relationshipId = relationship.getKey().orElse("");
+
+ Edge.Builder edgeBuilder = new Edge.Builder(relationship.getType()).id(relationshipId.toString());
+ edgeBuilder.source(vertexFromChampObject(relationship.getSource(),
+ relationship.getSource().getProperties()
+ .get(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
+ ? relationship.getSource().getType()
+ : relationship.getSource().getProperties()
+ .get(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()));
+ edgeBuilder.target(vertexFromChampObject(relationship.getTarget(),
+ relationship.getTarget().getProperties()
+ .get(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
+ ? relationship.getTarget().getType()
+ : relationship.getTarget().getProperties()
+ .get(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()));
+
+ for (String key : relationship.getProperties().keySet()) {
+ edgeBuilder.property(key, relationship.getProperties().get(key).toString());
+ }
+
+ return edgeBuilder.build();
+ }
+
+ /**
+ * Performs any necessary shut down operations when the DAO is no longer
+ * needed.
+ */
+ public void close() {
+
+ if (champApi != null) {
+
+ logger.info(CrudServiceMsgs.STOPPING_CHAMP_DAO);
+
+ champApi.shutdown();
+ }
+ }
+
+ @Override
+ public String openTransaction() {
+
+ ChampTransaction transaction = champApi.openTransaction();
+
+ transactions.put(transaction.id(), transaction);
+ logger.info(CrudServiceMsgs.TRANSACTION, "Stored transaction " + transaction.id() + " in hashmap");
+ logger.info(CrudServiceMsgs.TRANSACTION, "Hash map contents:");
+ for (String key : transactions.keySet()) {
+ logger.info(CrudServiceMsgs.TRANSACTION, key);
+ }
+ return transaction.id();
+ }
+
+ @Override
+ public void commitTransaction(String id) throws CrudException {
+
+ try {
+ champApi.commitTransaction(getTransaction(id));
+ } catch (ChampTransactionException e) {
+ throw new CrudException("Error while commiting transaction " + id,
+ javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ transactions.remove(id);
+ }
+
+ @Override
+ public void rollbackTransaction(String id) throws CrudException {
+
+ try {
+ champApi.rollbackTransaction(getTransaction(id));
+ } catch (ChampTransactionException e) {
+ throw new CrudException("Error while transaction rollback " + id,
+ javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ transactions.remove(id);
+ }
+
+ private ChampTransaction getTransaction(String id) throws CrudException {
+
+ logger.info(CrudServiceMsgs.TRANSACTION, "Looking up transaction " + id);
+ if (transactions.containsKey(id)) {
+ logger.info(CrudServiceMsgs.TRANSACTION, "Found it!");
+ return (transactions.get(id));
+ } else {
+ logger.info(CrudServiceMsgs.TRANSACTION, "Didn't find transaction id " + id + ". Hash map contains: ");
+ for (String key : transactions.keySet()) {
+ logger.info(CrudServiceMsgs.TRANSACTION, key);
+ }
+ throw new CrudException("No open transaction with id: " + id, javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public Vertex addVertex(String type, Map<String, Object> properties, String txId) throws CrudException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Add/update vertex: {label: " + type + " properties:" + propertiesMapToString(properties));
+ }
+
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ // Create an object to represent our vertex in the format expected by the
+ // Champ library.
+ ChampObject objectToCreate = buildChampObject(type, properties);
+
+ try {
+
+ // Ask the Champ library to store our vertex, placing the returned object
+ // into a
+ // list so that we can easily put that into our result object.
+ return vertexFromChampObject(champApi.storeObject(objectToCreate, Optional.of(getTransaction(txId))), type);
+
+ } catch (ChampMarshallingException | ChampSchemaViolationException | ChampObjectNotExistsException
+ | ChampTransactionException e) {
+
+ // Something went wrong - throw an exception.
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties, String txId)
+ throws CrudException {
+ // For now, assume source and target are straight ids...
+ try {
+
+ Optional<ChampObject> sourceObject = champApi.retrieveObject(Long.parseLong(source.getId().get()),
+ Optional.of(getTransaction(txId)));
+ if (!sourceObject.isPresent() || !sourceObject.get().getType().equals(source.getType())) {
+ throw new CrudException(
+ "Error creating edge - source vertex with id " + source + " does not exist in graph data base",
+ javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ }
+
+ Optional<ChampObject> targetObject = champApi.retrieveObject(Long.parseLong(target.getId().get()),
+ Optional.of(getTransaction(txId)));
+ if (!targetObject.isPresent() || !targetObject.get().getType().equals(target.getType())) {
+ throw new CrudException(
+ "Error creating edge - target vertex with id " + target + " does not exist in graph data base",
+ javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ }
+
+ // Now, create the ChampRelationship object for our edge and store it in
+ // the graph database.
+ return edgeFromChampRelationship(champApi.storeRelationship(
+ new ChampRelationship.Builder(sourceObject.get(), targetObject.get(), type).properties(properties).build(),
+ Optional.of(getTransaction(txId))));
+
+ } catch (ChampMarshallingException | ChampObjectNotExistsException | ChampSchemaViolationException
+ | ChampTransactionException | ChampRelationshipNotExistsException | ChampUnmarshallingException e) {
+
+ throw new CrudException("Error creating edge: " + e.getMessage(),
+ javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ }
+
+ @Override
+ public Vertex updateVertex(String id, String type, Map<String, Object> properties, String txId) throws CrudException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Update vertex with id: " + id + " with properties: " + propertiesMapToString(properties));
+ }
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ try {
+ // Now, build the updated version of the Champ Object...
+ ChampObject updateObject = buildChampObject(id, type, properties);
+ // ...and send it to the Champ library.
+ return vertexFromChampObject(champApi.replaceObject(updateObject, Optional.of(getTransaction(txId))), type);
+
+ } catch (ChampObjectNotExistsException e) {
+ throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ } catch (NumberFormatException | ChampMarshallingException | ChampTransactionException
+ | ChampSchemaViolationException e) {
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public boolean transactionExists(String id) throws CrudException {
+ return transactions.containsKey(id);
+ }
+
+ @Override
+ public void deleteVertex(String id, String type, String txId) throws CrudException {
+ try {
+
+ // First, retrieve the vertex that we intend to delete.
+ Optional<ChampObject> retrievedVertex = champApi.retrieveObject(Long.parseLong(id),
+ Optional.of(getTransaction(txId)));
+
+ // Did we find it?
+ if (!retrievedVertex.isPresent() || !retrievedVertex.get().getType().equals(type)) {
+ throw new CrudException("Failed to delete vertex with id: " + id + " - vertex does not exist.",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ // Now, verify that there are no edges incident to the vertex (they must
+ // be deleted
+ // first if so).
+ Stream<ChampRelationship> relationships = champApi.retrieveRelationships(retrievedVertex.get(),
+ Optional.of(getTransaction(txId)));
+
+ if (relationships.count() > 0) {
+ throw new CrudException("Attempt to delete vertex with id " + id + " which has incident edges.",
+ javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ }
+
+ // Finally, we can attempt to delete our vertex.
+ champApi.deleteObject(Long.parseLong(id), Optional.of(getTransaction(txId)));
+
+ } catch (NumberFormatException | ChampUnmarshallingException | ChampObjectNotExistsException
+ | ChampTransactionException e) {
+
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ }
+
+ @Override
+ public Edge updateEdge(Edge edge, String txId) throws CrudException {
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "Update edge with id: " + edge.getId() + " with properties: " + propertiesMapToString(edge.getProperties()));
+ }
+
+ try {
+ // Now, build the updated version of the Champ Relationship...
+ ChampRelationship updateRelationship = new ChampRelationship.Builder(
+ buildChampObject(edge.getSource().getId().get(), edge.getSource().getType(),
+ edge.getSource().getProperties()),
+ buildChampObject(edge.getTarget().getId().get(), edge.getTarget().getType(),
+ edge.getTarget().getProperties()),
+ edge.getType()).key(getRelKey(edge.getId().get())).properties(edge.getProperties()).build();
+ // ...and send it to the Champ library.
+ return edgeFromChampRelationship(
+ champApi.replaceRelationship(updateRelationship, Optional.of(getTransaction(txId))));
+
+ } catch (ChampRelationshipNotExistsException ex) {
+ throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ } catch (NumberFormatException | ChampUnmarshallingException | ChampMarshallingException
+ | ChampSchemaViolationException | ChampTransactionException ex) {
+
+ throw new CrudException(ex.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @Override
+ public void deleteEdge(String id, String type, String txId) throws CrudException {
+ try {
+
+ // First, retrieve the edge that we want to delete.
+ Optional<ChampRelationship> relationshipToDelete = champApi.retrieveRelationship(getRelKey(id),
+ Optional.of(getTransaction(txId)));
+
+ // Did we find it?
+ if (!relationshipToDelete.isPresent() || !relationshipToDelete.get().getType().equals(type)) {
+ throw new CrudException("Failed to delete edge with id: " + id + " - edge does not exist",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ // Now we can delete the edge.
+ champApi.deleteRelationship(relationshipToDelete.get(), Optional.of(getTransaction(txId)));
+
+ } catch (ChampRelationshipNotExistsException | NumberFormatException | ChampUnmarshallingException
+ | ChampTransactionException e) {
+
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ }
+
+ @Override
+ public Edge getEdge(String id, String type, String txId) throws CrudException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Get edge with id: " + id);
+ }
+
+ try {
+
+ // Request the edge from the graph db.
+ Optional<ChampRelationship> relationship = champApi.retrieveRelationship(getRelKey(id),
+ Optional.of(getTransaction(txId)));
+
+ // Did we find it?
+ if (relationship.isPresent() && relationship.get().getType().equals(type)) {
+
+ // Yup - return the result.
+ return edgeFromChampRelationship(relationship.get());
+
+ } else {
+
+ // We didn't find an edge with the supplied id, so throw an exception.
+ throw new CrudException("No edge with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+
+ } catch (ChampUnmarshallingException | ChampTransactionException e) {
+
+ // Something went wrong, so throw an exception.
+ throw new CrudException(e.getMessage(), javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/dao/champion/ChampionDao.java b/src/main/java/org/onap/crud/dao/champion/ChampionDao.java
new file mode 100644
index 0000000..4bde2e0
--- /dev/null
+++ b/src/main/java/org/onap/crud/dao/champion/ChampionDao.java
@@ -0,0 +1,623 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.dao.champion;
+
+import net.dongliu.gson.GsonJava8TypeAdapterFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.message.BasicNameValuePair;
+import org.eclipse.jetty.util.security.Password;
+import org.onap.aai.logging.LoggingContext;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+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.util.CrudServiceConstants;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.slf4j.MDC;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+public class ChampionDao implements GraphDao {
+ private RestClient client;
+ private String baseUrl;
+
+ private static final String HEADER_FROM_APP = "X-FromAppId";
+ private static final String HEADER_TRANS_ID = "X-TransactionId";
+
+ private Logger logger = LoggerFactory.getInstance().getLogger(ChampionDao.class.getName());
+
+ // We use a custom vertex serializer for Champion because it expects "key"
+ // instead of "id"
+ private static final Gson championGson = new GsonBuilder()
+ .registerTypeAdapterFactory(new GsonJava8TypeAdapterFactory())
+ .registerTypeAdapter(Vertex.class, new ChampionVertexSerializer())
+ .registerTypeAdapter(Edge.class, new ChampionEdgeSerializer()).create();
+
+ public ChampionDao(String championUrl, String certPassword) {
+ try {
+ client = new RestClient().authenticationMode(RestAuthenticationMode.SSL_CERT).validateServerHostname(false)
+ .validateServerCertChain(false).clientCertFile(CrudServiceConstants.CRD_CHAMPION_AUTH_FILE)
+ .clientCertPassword(Password.deobfuscate(certPassword));
+
+ baseUrl = championUrl;
+ } catch (Exception e) {
+ System.out.println("Error setting up Champion configuration");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ @Override
+ public Vertex getVertex(String id) throws CrudException {
+ String url = baseUrl + "objects/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ return Vertex.fromJson(getResult.getResult());
+ } else {
+ // We didn't find a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public Vertex getVertex(String id, String type) throws CrudException {
+ String url = baseUrl + "objects/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ Vertex vert = Vertex.fromJson(getResult.getResult());
+
+ if (!vert.getType().equalsIgnoreCase(type)) {
+ // 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);
+ }
+ return vert;
+ } else {
+ // We didn't find a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public List<Edge> getVertexEdges(String id) throws CrudException {
+ String url = baseUrl + "objects/relationships/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ return championGson.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 new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public List<Vertex> getVertices(String type, Map<String, Object> filter) throws CrudException {
+ filter.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ String url = baseUrl + "objects/filter" + "?"
+ + URLEncodedUtils.format(convertToNameValuePair(filter), Charset.defaultCharset());
+
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ return championGson.fromJson(getResult.getResult(), new TypeToken<List<Vertex>>() {
+ }.getType());
+ } else {
+ // We didn't find a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("No vertices found in graph for given filters",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public Edge getEdge(String id, String type) throws CrudException {
+ String url = baseUrl + "relationships/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ Edge edge = Edge.fromJson(getResult.getResult());
+
+ if (!edge.getType().equalsIgnoreCase(type)) {
+ // 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);
+ }
+ return edge;
+ } else {
+ // We didn't find a edge with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("No edge with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public List<Edge> getEdges(String type, Map<String, Object> filter) throws CrudException {
+ String url = baseUrl + "relationships/filter" + "?"
+ + URLEncodedUtils.format(convertToNameValuePair(filter), Charset.defaultCharset());
+
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ return championGson.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 new CrudException("No edges found in graph for given filters", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public Vertex addVertex(String type, Map<String, Object> properties) throws CrudException {
+ String url = baseUrl + "objects";
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ // TODO: This probably shouldn't be here
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ Vertex.Builder insertVertexBuilder = new Vertex.Builder(type);
+ properties.forEach(insertVertexBuilder::property);
+ Vertex insertVertex = insertVertexBuilder.build();
+
+ OperationResult getResult = client.post(url, insertVertex.toJson(), headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) {
+ return Vertex.fromJson(getResult.getResult());
+ } else {
+ // We didn't create a vertex with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("Failed to create vertex", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public Vertex updateVertex(String id, String type, Map<String, Object> properties) throws CrudException {
+ String url = baseUrl + "objects/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ // TODO: This probably shouldn't be here
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ Vertex.Builder insertVertexBuilder = new Vertex.Builder(type);
+ insertVertexBuilder.id(id);
+ properties.forEach(insertVertexBuilder::property);
+ Vertex insertVertex = insertVertexBuilder.build();
+
+ String payload = insertVertex.toJson(championGson);
+ OperationResult getResult = client.put(url, payload, headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) {
+ return Vertex.fromJson(getResult.getResult());
+ } else {
+ // We didn't create a vertex with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("Failed to update vertex", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public void deleteVertex(String id, String type) throws CrudException {
+ String url = baseUrl + "objects/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.delete(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() != Response.Status.OK.getStatusCode()) {
+ // We didn't delete a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("Failed to delete vertex", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties) throws CrudException {
+ String url = baseUrl + "relationships";
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ // Try requests to ensure source and target exist in Champion
+ Vertex dbSource = getVertex(source.getId().get(), source.getType());
+ Vertex dbTarget = getVertex(target.getId().get(), target.getType());
+
+ Edge.Builder insertEdgeBuilder = new Edge.Builder(type).source(dbSource).target(dbTarget);
+ properties.forEach(insertEdgeBuilder::property);
+ Edge insertEdge = insertEdgeBuilder.build();
+
+ String edgeJson = insertEdge.toJson(championGson);
+ OperationResult getResult = client.post(url, edgeJson, headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) {
+ return Edge.fromJson(getResult.getResult());
+ } else {
+ // We didn't create an edge with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("Failed to create edge", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public Edge updateEdge(Edge edge) throws CrudException {
+ if (!edge.getId().isPresent()) {
+ throw new CrudException("Unable to identify edge: " + edge.toString(), Response.Status.BAD_REQUEST);
+ }
+ String url = baseUrl + "relationships/" + edge.getId().get();
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ String edgeJson = edge.toJson(championGson);
+ OperationResult getResult = client.put(url, edgeJson, headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) {
+ return Edge.fromJson(getResult.getResult());
+ } else {
+ // We didn't create an edge with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("Failed to update edge", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public void deleteEdge(String id, String type) throws CrudException {
+ String url = baseUrl + "relationships/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.delete(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() != 200) {
+ // We didn't find an edge with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("No edge with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public String openTransaction() {
+ String url = baseUrl + "transaction";
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.post(url, "", headers, MediaType.TEXT_PLAIN_TYPE, MediaType.TEXT_PLAIN_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ return getResult.getResult();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void commitTransaction(String id) throws CrudException {
+ String url = baseUrl + "transaction/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.put(url, "{\"method\": \"commit\"}", headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.TEXT_PLAIN_TYPE);
+
+ if (getResult.getResultCode() != 200) {
+ throw new CrudException("Unable to commit transaction",
+ Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public void rollbackTransaction(String id) throws CrudException {
+ String url = baseUrl + "transaction/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.put(url, "{\"method\": \"rollback\"}", headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.TEXT_PLAIN_TYPE);
+
+ if (getResult.getResultCode() != 200) {
+ throw new CrudException("Unable to rollback transaction",
+ Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public boolean transactionExists(String id) throws CrudException {
+ String url = baseUrl + "transaction/" + id;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ return getResult.getResultCode() == 200;
+ }
+
+ @Override
+ public Vertex addVertex(String type, Map<String, Object> properties, String txId) throws CrudException {
+ String url = baseUrl + "objects?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ // TODO: This probably shouldn't be here
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ Vertex.Builder insertVertexBuilder = new Vertex.Builder(type);
+ properties.forEach(insertVertexBuilder::property);
+ Vertex insertVertex = insertVertexBuilder.build();
+
+ OperationResult getResult = client.post(url, insertVertex.toJson(), headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) {
+ return Vertex.fromJson(getResult.getResult());
+ } else {
+ // We didn't create a vertex with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("Failed to create vertex", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public Edge addEdge(String type, Vertex source, Vertex target, Map<String, Object> properties, String txId)
+ throws CrudException {
+ String url = baseUrl + "relationships?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ // Try requests to ensure source and target exist in Champion
+ Vertex dbSource = getVertex(source.getId().get(), source.getType(), txId);
+ Vertex dbTarget = getVertex(target.getId().get(), target.getType(), txId);
+
+ Edge.Builder insertEdgeBuilder = new Edge.Builder(type).source(dbSource).target(dbTarget);
+ properties.forEach(insertEdgeBuilder::property);
+ Edge insertEdge = insertEdgeBuilder.build();
+
+ OperationResult getResult = client.post(url, insertEdge.toJson(championGson), headers,
+ MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.CREATED.getStatusCode()) {
+ return Edge.fromJson(getResult.getResult());
+ } else {
+ // We didn't create an edge with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("Failed to create edge", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public Vertex updateVertex(String id, String type, Map<String, Object> properties, String txId) throws CrudException {
+ String url = baseUrl + "objects/" + id + "?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ // Add the aai_node_type so that AAI can read the data created by gizmo
+ // TODO: This probably shouldn't be here
+ properties.put(org.onap.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+ Vertex.Builder insertVertexBuilder = new Vertex.Builder(type);
+ insertVertexBuilder.id(id);
+ properties.forEach(insertVertexBuilder::property);
+ Vertex insertVertex = insertVertexBuilder.build();
+
+ String payload = insertVertex.toJson(championGson);
+ OperationResult getResult = client.put(url, payload, headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) {
+ return Vertex.fromJson(getResult.getResult());
+ } else {
+ // We didn't create a vertex with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("Failed to update vertex", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public void deleteVertex(String id, String type, String txId) throws CrudException {
+ String url = baseUrl + "objects/" + id + "?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.delete(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() != Response.Status.OK.getStatusCode()) {
+ // We didn't delete a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("Failed to delete vertex", Response.Status.fromStatusCode(getResult.getResultCode()));
+ }
+ }
+
+ @Override
+ public Edge updateEdge(Edge edge, String txId) throws CrudException {
+ if (!edge.getId().isPresent()) {
+ throw new CrudException("Unable to identify edge: " + edge.toString(), Response.Status.BAD_REQUEST);
+ }
+ String url = baseUrl + "relationships/" + edge.getId().get() + "?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.put(url, edge.toJson(championGson), headers, MediaType.APPLICATION_JSON_TYPE,
+ MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == Response.Status.OK.getStatusCode()) {
+ return Edge.fromJson(getResult.getResult());
+ } else {
+ // 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()));
+ }
+ }
+
+ @Override
+ public void deleteEdge(String id, String type, String txId) throws CrudException {
+ String url = baseUrl + "relationships/" + id + "?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.delete(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() != 200) {
+ // We didn't find an edge with the supplied type, so just throw an
+ // exception.
+ throw new CrudException("No edge with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ @Override
+ public Edge getEdge(String id, String type, String txId) throws CrudException {
+ String url = baseUrl + "relationships/" + id + "?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ Edge edge = Edge.fromJson(getResult.getResult());
+
+ if (!edge.getType().equalsIgnoreCase(type)) {
+ // 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);
+ }
+ return edge;
+ } else {
+ // We didn't find an edge with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("No edge with id " + id + " found in graph", javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ public Vertex getVertex(String id, String type, String txId) throws CrudException {
+ String url = baseUrl + "objects/" + id + "?transactionId=" + txId;
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put(HEADER_FROM_APP, Arrays.asList("Gizmo"));
+ headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+ OperationResult getResult = client.get(url, headers, MediaType.APPLICATION_JSON_TYPE);
+
+ if (getResult.getResultCode() == 200) {
+ Vertex vert = Vertex.fromJson(getResult.getResult());
+
+ if (!vert.getType().equalsIgnoreCase(type)) {
+ // 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);
+ }
+ return vert;
+ } else {
+ // We didn't find a vertex with the supplied id, so just throw an
+ // exception.
+ throw new CrudException("No vertex with id " + id + " found in graph",
+ javax.ws.rs.core.Response.Status.NOT_FOUND);
+ }
+ }
+
+ // https://stackoverflow.com/questions/26942330/convert-mapstring-string-to-listnamevaluepair-is-this-the-most-efficient
+ private List<NameValuePair> convertToNameValuePair(Map<String, Object> pairs) {
+ List<NameValuePair> nvpList = new ArrayList<>(pairs.size());
+
+ pairs.forEach((key, value) -> nvpList.add(new BasicNameValuePair(key, value.toString())));
+
+ return nvpList;
+ }
+}
diff --git a/src/main/java/org/onap/crud/dao/champion/ChampionEdgeSerializer.java b/src/main/java/org/onap/crud/dao/champion/ChampionEdgeSerializer.java
new file mode 100644
index 0000000..655d096
--- /dev/null
+++ b/src/main/java/org/onap/crud/dao/champion/ChampionEdgeSerializer.java
@@ -0,0 +1,49 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.dao.champion;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+import org.onap.crud.entity.Edge;
+import org.onap.crud.entity.Vertex;
+
+import java.lang.reflect.Type;
+
+public class ChampionEdgeSerializer implements JsonSerializer<Edge> {
+ @Override
+ public JsonElement serialize(Edge edge, Type type, JsonSerializationContext jsonSerializationContext) {
+ final JsonObject edgeObj = new JsonObject();
+ if (edge.getId().isPresent()) {
+ edgeObj.add("key", jsonSerializationContext.serialize(edge.getId().get()));
+ }
+ edgeObj.add("type", jsonSerializationContext.serialize(edge.getType()));
+ edgeObj.add("properties", jsonSerializationContext.serialize(edge.getProperties()));
+ edgeObj.add("source", jsonSerializationContext.serialize(edge.getSource()));
+ edgeObj.add("target", jsonSerializationContext.serialize(edge.getTarget()));
+ return edgeObj;
+ }
+}
diff --git a/src/main/java/org/onap/crud/dao/champion/ChampionVertexSerializer.java b/src/main/java/org/onap/crud/dao/champion/ChampionVertexSerializer.java
new file mode 100644
index 0000000..904ad2e
--- /dev/null
+++ b/src/main/java/org/onap/crud/dao/champion/ChampionVertexSerializer.java
@@ -0,0 +1,47 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.dao.champion;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+import org.onap.crud.entity.Vertex;
+
+import java.lang.reflect.Type;
+
+public class ChampionVertexSerializer implements JsonSerializer<Vertex> {
+ @Override
+ public JsonElement serialize(Vertex vertex, Type type, JsonSerializationContext jsonSerializationContext) {
+ final JsonObject vertexObj = new JsonObject();
+ if (vertex.getId().isPresent()) {
+ vertexObj.add("key", jsonSerializationContext.serialize(vertex.getId().get()));
+ }
+ vertexObj.add("type", jsonSerializationContext.serialize(vertex.getType()));
+ vertexObj.add("properties", jsonSerializationContext.serialize(vertex.getProperties()));
+
+ return vertexObj;
+ }
+}
diff --git a/src/main/java/org/onap/crud/entity/Edge.java b/src/main/java/org/onap/crud/entity/Edge.java
new file mode 100644
index 0000000..87b0ac4
--- /dev/null
+++ b/src/main/java/org/onap/crud/entity/Edge.java
@@ -0,0 +1,140 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.entity;
+
+import net.dongliu.gson.GsonJava8TypeAdapterFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class Edge {
+ private static final Gson gson = new GsonBuilder().registerTypeAdapterFactory(new GsonJava8TypeAdapterFactory())
+ .create();
+
+ @SerializedName(value = "id", alternate = { "key" })
+ private final Optional<String> id;
+ private final String type;
+ private final Map<String, Object> properties;
+ private final Vertex source;
+ private final Vertex target;
+
+ private Edge(Builder builder) {
+ this.id = builder.id;
+ this.type = builder.type;
+ this.source = builder.source;
+ this.target = builder.target;
+ this.properties = builder.properties;
+ }
+
+ public static class Builder {
+ private Optional<String> id = Optional.empty();
+ private final String type;
+ private Vertex source;
+ private Vertex target;
+ private final Map<String, Object> properties = new HashMap<String, Object>();
+
+ public Builder(String type) {
+ if (type == null) {
+ throw new IllegalArgumentException("Type cannot be null");
+ }
+
+ this.type = type;
+ }
+
+ public Builder id(String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("id cannot be null");
+ }
+
+ this.id = Optional.of(id);
+ return this;
+ }
+
+ public Builder property(String key, Object value) {
+ if (key == null || value == null) {
+ throw new IllegalArgumentException("Property key/value cannot be null");
+ }
+ properties.put(key, value);
+ return this;
+ }
+
+ public Builder source(Vertex source) {
+ this.source = source;
+ return this;
+ }
+
+ public Builder target(Vertex target) {
+ this.target = target;
+ return this;
+ }
+
+ public Edge build() {
+ return new Edge(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Edge [id=" + id + ", type=" + type + ", properties=" + properties + ", source=" + source + ", target="
+ + target + "]";
+ }
+
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ public String toJson(Gson customGson) {
+ return customGson.toJson(this);
+ }
+
+ public static Edge fromJson(String jsonString) {
+ return gson.fromJson(jsonString, Edge.class);
+ }
+
+ public Optional<String> getId() {
+ return id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ public Vertex getSource() {
+ return source;
+ }
+
+ public Vertex getTarget() {
+ return target;
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/entity/Vertex.java b/src/main/java/org/onap/crud/entity/Vertex.java
new file mode 100644
index 0000000..42d0eef
--- /dev/null
+++ b/src/main/java/org/onap/crud/entity/Vertex.java
@@ -0,0 +1,115 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.entity;
+
+import net.dongliu.gson.GsonJava8TypeAdapterFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class Vertex {
+ private static final Gson gson = new GsonBuilder().registerTypeAdapterFactory(new GsonJava8TypeAdapterFactory())
+ .create();
+
+ @SerializedName(value = "id", alternate = { "key" })
+ private final Optional<String> id;
+
+ private final String type;
+ private final Map<String, Object> properties;
+
+ private Vertex(Builder builder) {
+ this.id = builder.id;
+ this.type = builder.type;
+ this.properties = builder.properties;
+ }
+
+ public static class Builder {
+ private Optional<String> id = Optional.empty();
+ private final String type;
+ private final Map<String, Object> properties = new HashMap<String, Object>();
+
+ public Builder(String type) {
+ if (type == null) {
+ throw new IllegalArgumentException("Type cannot be null");
+ }
+ this.type = type;
+ }
+
+ public Builder id(String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("id cannot be null");
+ }
+
+ this.id = Optional.of(id);
+ return this;
+ }
+
+ public Builder property(String key, Object value) {
+ if (key == null || value == null) {
+ throw new IllegalArgumentException("Property key/value cannot be null");
+ }
+ properties.put(key, value);
+ return this;
+ }
+
+ public Vertex build() {
+ return new Vertex(this);
+ }
+ }
+
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ public String toJson(Gson customGson) {
+ return customGson.toJson(this);
+ }
+
+ public static Vertex fromJson(String jsonString) {
+ return gson.fromJson(jsonString, Vertex.class);
+ }
+
+ @Override
+ public String toString() {
+ return "Vertex [id=" + id + ", type=" + type + ", properties=" + properties + "]";
+ }
+
+ public Optional<String> getId() {
+ return id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/event/GraphEvent.java b/src/main/java/org/onap/crud/event/GraphEvent.java
new file mode 100644
index 0000000..9e9c44c
--- /dev/null
+++ b/src/main/java/org/onap/crud/event/GraphEvent.java
@@ -0,0 +1,235 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.event;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.annotations.SerializedName;
+
+import org.onap.crud.exception.CrudException;
+
+import javax.ws.rs.core.Response.Status;
+
+public class GraphEvent {
+
+ public enum GraphEventOperation {
+ CREATE, UPDATE, DELETE
+ }
+
+ public enum GraphEventResult {
+ SUCCESS, FAILURE
+ }
+
+ private GraphEventOperation operation;
+
+ @SerializedName("transaction-id")
+ private String transactionId;
+
+ private long timestamp;
+
+ private GraphEventVertex vertex;
+
+ private GraphEventEdge edge;
+
+ private GraphEventResult result;
+
+ @SerializedName("error-message")
+ private String errorMessage;
+
+ private Status httpErrorStatus;
+
+ /**
+ * Marshaller/unmarshaller for converting to/from JSON.
+ */
+ private static final Gson gson = new GsonBuilder().disableHtmlEscaping()
+ .setPrettyPrinting().create();
+
+ public static Builder builder(GraphEventOperation operation) {
+ return new Builder(operation);
+ }
+
+ public GraphEventOperation getOperation() {
+ return operation;
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public GraphEventVertex getVertex() {
+ return vertex;
+ }
+
+ public GraphEventEdge getEdge() {
+ return edge;
+ }
+
+ public GraphEventResult getResult() {
+ return result;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setResult(GraphEventResult result) {
+ this.result = result;
+ }
+
+
+ public Status getHttpErrorStatus() {
+ return httpErrorStatus;
+ }
+
+ public void setHttpErrorStatus(Status httpErrorStatus) {
+ this.httpErrorStatus = httpErrorStatus;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public void setVertex(GraphEventVertex vertex) {
+ this.vertex = vertex;
+ }
+
+ public void setEdge(GraphEventEdge edge) {
+ this.edge = edge;
+ }
+
+ /**
+ * Unmarshalls this Vertex object into a JSON string.
+ *
+ * @return - A JSON format string representation of this Vertex.
+ */
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ /**
+ * Marshalls the provided JSON string into a Vertex object.
+ *
+ * @param json - The JSON string to produce the Vertex from.
+ * @return - A Vertex object.
+ * @throws SpikeException
+ */
+ public static GraphEvent fromJson(String json) throws CrudException {
+
+ try {
+
+ // Make sure that we were actually provided a non-empty string
+ // before we
+ // go any further.
+ if (json == null || json.isEmpty()) {
+ throw new CrudException("Empty or null JSON string.", Status.BAD_REQUEST);
+ }
+
+ // Marshall the string into a Vertex object.
+ return gson.fromJson(json, GraphEvent.class);
+
+ } catch (Exception ex) {
+ throw new CrudException("Unable to parse JSON string: ", Status.BAD_REQUEST);
+ }
+ }
+
+ @Override
+ public String toString() {
+
+ return toJson();
+ }
+
+ public String getObjectKey() {
+ if (this.getVertex() != null) {
+ return this.getVertex().getId();
+ } else if (this.getEdge() != null) {
+ return this.getEdge().getId();
+ }
+
+ return null;
+
+ }
+
+ public String getObjectType() {
+ if (this.getVertex() != null) {
+ return "vertex->" + this.getVertex().getType();
+ } else if (this.getEdge() != null) {
+ return "edge->" + this.getEdge().getType();
+ }
+
+ return null;
+
+ }
+
+ public static class Builder {
+
+ GraphEvent event = null;
+
+ public Builder(GraphEventOperation operation) {
+ event = new GraphEvent();
+ event.operation = operation;
+ }
+
+ public Builder vertex(GraphEventVertex vertex) {
+ event.vertex = vertex;
+ return this;
+ }
+
+ public Builder edge(GraphEventEdge edge) {
+ event.edge = edge;
+ return this;
+ }
+
+ public Builder result(GraphEventResult result) {
+ event.result = result;
+ return this;
+ }
+
+ public Builder errorMessage(String errorMessage) {
+ event.errorMessage = errorMessage;
+ return this;
+ }
+
+ public Builder httpErrorStatus(Status httpErrorStatus) {
+ event.httpErrorStatus = httpErrorStatus;
+ return this;
+ }
+
+ public GraphEvent build() {
+
+ event.timestamp = System.currentTimeMillis();
+ event.transactionId = java.util.UUID.randomUUID().toString();
+
+ return event;
+ }
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/event/GraphEventEdge.java b/src/main/java/org/onap/crud/event/GraphEventEdge.java
new file mode 100644
index 0000000..58ea4a7
--- /dev/null
+++ b/src/main/java/org/onap/crud/event/GraphEventEdge.java
@@ -0,0 +1,212 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.event;
+
+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.SerializedName;
+import com.google.gson.reflect.TypeToken;
+
+import org.onap.crud.entity.Edge;
+import org.onap.crud.entity.Vertex;
+import org.onap.crud.exception.CrudException;
+
+import java.util.Map;
+import javax.ws.rs.core.Response.Status;
+
+/**
+ * This class provides a generic representation of an Edge as provided by the
+ * graph data store.
+ */
+public class GraphEventEdge {
+
+ /**
+ * The unique identifier used to identify this edge in the graph data store.
+ */
+ @SerializedName("key")
+ private String id;
+
+ @SerializedName("schema-version")
+ private String modelVersion;
+
+ /**
+ * Type label assigned to this vertex.
+ */
+ private String type;
+
+ /**
+ * Source vertex for our edge.
+ */
+ private GraphEventVertex source;
+
+ /**
+ * Target vertex for our edge.
+ */
+ private GraphEventVertex target;
+
+ /**
+ * Map of all of the properties assigned to this vertex.
+ */
+ private JsonElement properties;
+
+ /**
+ * Marshaller/unmarshaller for converting to/from JSON.
+ */
+ private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
+ public GraphEventEdge(String id, String modelVersion, String type, GraphEventVertex source,
+ GraphEventVertex target, JsonElement properties) {
+ this.id = id;
+ this.modelVersion = modelVersion;
+ this.type = type;
+ this.source = source;
+ this.target = target;
+ this.properties = properties;
+ }
+
+ public GraphEventEdge() {
+
+ }
+
+ 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 GraphEventVertex getSource() {
+ return source;
+ }
+
+ public void setSource(GraphEventVertex source) {
+ this.source = source;
+ }
+
+ public GraphEventVertex getTarget() {
+ return target;
+ }
+
+ public void setTarget(GraphEventVertex target) {
+ this.target = target;
+ }
+
+ public JsonElement getProperties() {
+ return properties;
+ }
+
+ public void setProperties(JsonElement properties) {
+ this.properties = properties;
+ }
+
+ public String getModelVersion() {
+ return modelVersion;
+ }
+
+ public void setModelVersion(String modelVersion) {
+ this.modelVersion = modelVersion;
+ }
+
+ /**
+ * Unmarshalls this Edge object into a JSON string.
+ *
+ * @return - A JSON format string representation of this Edge.
+ */
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ /**
+ * Marshalls the provided JSON string into a Edge object.
+ *
+ * @param json - The JSON string to produce the Edge from.
+ * @return - A Edge object.
+ * @throws SpikeException
+ */
+ public static GraphEventEdge fromJson(String json) throws CrudException {
+
+ try {
+
+ // Make sure that we were actually provided a non-empty string
+ // before we
+ // go any further.
+ if (json == null || json.isEmpty()) {
+ throw new CrudException("Unable to parse JSON string: ", Status.BAD_REQUEST);
+ }
+
+ // Marshall the string into an Edge object.
+ return gson.fromJson(json, GraphEventEdge.class);
+
+ } catch (Exception ex) {
+ throw new CrudException("Unable to parse JSON string: ", Status.BAD_REQUEST);
+ }
+ }
+
+ public static GraphEventEdge fromEdge(Edge edge, String modelVersion) {
+
+ java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
+ JsonObject props = gson.toJsonTree(edge.getProperties(), mapType).getAsJsonObject();
+
+ GraphEventEdge graphEventEdge = new GraphEventEdge(edge.getId().orElse(""), modelVersion,
+ edge.getType(), new GraphEventVertex(edge.getSource().getId().orElse(""), null,
+ edge.getSource().getType(), null), new GraphEventVertex(edge.getTarget().getId().orElse(""),
+ null, edge.getTarget().getType(), null), props);
+
+ return graphEventEdge;
+
+ }
+
+ public Edge toEdge() {
+ Edge.Builder builder = new Edge.Builder(this.getType()).id(this.getId());
+ if (this.getSource() != null) {
+ builder.source(new Vertex.Builder(this.getSource().getType()).id(this.getSource().getId())
+ .build());
+ }
+ if (this.getTarget() != null) {
+ builder.target(new Vertex.Builder(this.getTarget().getType()).id(this.getTarget().getId())
+ .build());
+ }
+
+ if (this.getProperties() != null) {
+ java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
+ Map<String, Object> propertiesMap = gson.fromJson(this.getProperties(), mapType);
+ for (String key : propertiesMap.keySet()) {
+ builder.property(key, propertiesMap.get(key));
+ }
+ }
+ return builder.build();
+
+ }
+}
diff --git a/src/main/java/org/onap/crud/event/GraphEventVertex.java b/src/main/java/org/onap/crud/event/GraphEventVertex.java
new file mode 100644
index 0000000..d9a06d4
--- /dev/null
+++ b/src/main/java/org/onap/crud/event/GraphEventVertex.java
@@ -0,0 +1,181 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.event;
+
+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.SerializedName;
+import com.google.gson.reflect.TypeToken;
+
+import org.onap.crud.entity.Vertex;
+import org.onap.crud.exception.CrudException;
+
+import java.util.Map;
+import javax.ws.rs.core.Response.Status;
+
+/**
+ * This class provides a generic representation of a Vertex as provided by the
+ * graph data store.
+ */
+public class GraphEventVertex {
+
+ /**
+ * The unique identifier used to identify this vertex in the graph data
+ * store.
+ */
+ @SerializedName("key")
+ private String id;
+
+ @SerializedName("schema-version")
+ private String modelVersion;
+
+ /**
+ * Type label assigned to this vertex.
+ */
+ private String type;
+
+ /**
+ * Map of all of the properties assigned to this vertex.
+ */
+ private JsonElement properties;
+
+ /**
+ * Marshaller/unmarshaller for converting to/from JSON.
+ */
+ private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
+ public GraphEventVertex(String id, String modelVersion, String type, JsonElement properties) {
+ this.id = id;
+ this.modelVersion = modelVersion;
+ this.type = type;
+ this.properties = properties;
+ }
+
+ public GraphEventVertex() {
+
+ }
+
+ 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 JsonElement getProperties() {
+ return properties;
+ }
+
+ public void setProperties(JsonElement properties) {
+ this.properties = properties;
+ }
+
+ public String getModelVersion() {
+ return modelVersion;
+ }
+
+ public void setModelVersion(String modelVersion) {
+ this.modelVersion = modelVersion;
+ }
+
+ /**
+ * Unmarshalls this Vertex object into a JSON string.
+ *
+ * @return - A JSON format string representation of this Vertex.
+ */
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ /**
+ * Marshalls the provided JSON string into a Vertex object.
+ *
+ * @param json - The JSON string to produce the Vertex from.
+ * @return - A Vertex object.
+ * @throws SpikeException
+ */
+ public static GraphEventVertex fromJson(String json) throws CrudException {
+
+ try {
+
+ // Make sure that we were actually provided a non-empty string
+ // before we
+ // go any further.
+ if (json == null || json.isEmpty()) {
+ throw new CrudException("Empty or null JSON string.", Status.BAD_REQUEST);
+ }
+
+ // Marshall the string into a Vertex object.
+ return gson.fromJson(json, GraphEventVertex.class);
+
+ } catch (Exception ex) {
+ throw new CrudException("Unable to parse JSON string: ", Status.BAD_REQUEST);
+ }
+ }
+
+ @Override
+ public String toString() {
+
+ return toJson();
+ }
+
+ public static GraphEventVertex fromVertex(Vertex vertex, String modelVersion) {
+
+ java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
+ JsonObject props = gson.toJsonTree(vertex.getProperties(), mapType).getAsJsonObject();
+ GraphEventVertex graphEventVertex = new GraphEventVertex(vertex.getId().orElse(""),
+ modelVersion, vertex.getType(), props);
+ return graphEventVertex;
+
+ }
+
+ public Vertex toVertex() {
+ Vertex.Builder builder = new Vertex.Builder(this.getType()).id(this.getId());
+
+ if (this.getProperties() != null) {
+ java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
+ Map<String, Object> propertiesMap = gson.fromJson(this.getProperties(), mapType);
+ for (String key : propertiesMap.keySet()) {
+ builder.property(key, propertiesMap.get(key));
+ }
+ }
+
+ return builder.build();
+
+ }
+
+
+}
diff --git a/src/main/java/org/onap/crud/exception/CrudException.java b/src/main/java/org/onap/crud/exception/CrudException.java
new file mode 100644
index 0000000..a3d3127
--- /dev/null
+++ b/src/main/java/org/onap/crud/exception/CrudException.java
@@ -0,0 +1,62 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.exception;
+
+import javax.ws.rs.core.Response.Status;
+
+public class CrudException extends Exception {
+
+ private static final long serialVersionUID = 8162385108397238865L;
+
+ private Status httpStatus;
+
+ public CrudException() {
+ }
+
+ public CrudException(String message, Status httpStatus) {
+ super(message);
+ this.setHttpStatus(httpStatus);
+ }
+
+ public CrudException(Throwable cause) {
+ super(cause);
+ }
+
+ public CrudException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public CrudException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public Status getHttpStatus() {
+ return httpStatus;
+ }
+
+ public void setHttpStatus(Status httpStatus) {
+ this.httpStatus = httpStatus;
+ }
+}
diff --git a/src/main/java/org/onap/crud/logging/CrudServiceMsgs.java b/src/main/java/org/onap/crud/logging/CrudServiceMsgs.java
new file mode 100644
index 0000000..6b04a0f
--- /dev/null
+++ b/src/main/java/org/onap/crud/logging/CrudServiceMsgs.java
@@ -0,0 +1,87 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.logging;
+
+import com.att.eelf.i18n.EELFResourceManager;
+
+import org.onap.aai.cl.eelf.LogMessageEnum;
+
+public enum CrudServiceMsgs implements LogMessageEnum {
+
+ /**
+ * Received request {0} {1} from {2}. Sending response: {3}
+ *
+ * <p>
+ * Arguments: {0} = operation {1} = target URL {2} = source {3} = response
+ * code
+ */
+ PROCESS_REST_REQUEST,
+
+ INVALID_OXM_FILE, INVALID_OXM_DIR, OXM_FILE_CHANGED, TRANSACTION,
+
+ /**
+ * Successfully loaded schema: {0}
+ *
+ * <p>
+ * Arguments: {0} = oxm filename
+ */
+ LOADED_OXM_FILE,
+
+ /**
+ * Unable to load OXM schema: {0}
+ *
+ * <p>
+ * Arguments: {0} = error
+ */
+ OXM_LOAD_ERROR,
+
+ /**
+ * Stopping ChampDAO...
+ *
+ * <p>
+ * Arguments:
+ */
+ STOPPING_CHAMP_DAO,
+
+ /**
+ * Failure instantiating CRUD Rest Service. Cause: {0}
+ *
+ * <p>
+ * Arguments: {0} - Failure cause.
+ */
+ INSTANTIATE_AUTH_ERR,
+
+ /**
+ * Arguments: {0} Opertaion {1} URI {2} = Exception
+ */
+ EXCEPTION_DURING_METHOD_CALL;
+
+ /**
+ * Static initializer to ensure the resource bundles for this class are
+ * loaded...
+ */
+ static {
+ EELFResourceManager.loadMessageBundle("logging/CrudServiceMsgs");
+ }
+}
diff --git a/src/main/java/org/onap/crud/logging/LoggingUtil.java b/src/main/java/org/onap/crud/logging/LoggingUtil.java
new file mode 100644
index 0000000..453dc9d
--- /dev/null
+++ b/src/main/java/org/onap/crud/logging/LoggingUtil.java
@@ -0,0 +1,82 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.logging;
+
+import org.onap.aai.cl.api.LogFields;
+import org.onap.aai.cl.api.LogLine;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.crud.util.CrudServiceConstants;
+import org.slf4j.MDC;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+public class LoggingUtil {
+ /**
+ * Initializes mdc context.
+ */
+ public static void initMdcContext(HttpServletRequest httpReq, HttpHeaders headers) {
+ String fromIp = httpReq.getRemoteAddr();
+ String fromAppId = "";
+ String transId = null;
+
+ if (headers.getRequestHeaders().getFirst("X-FromAppId") != null) {
+ fromAppId = headers.getRequestHeaders().getFirst("X-FromAppId");
+ }
+
+ if ((headers.getRequestHeaders().getFirst("X-TransactionId") == null)
+ || headers.getRequestHeaders().getFirst("X-TransactionId").isEmpty()) {
+ transId = java.util.UUID.randomUUID().toString();
+ } else {
+ transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ }
+
+ MdcContext.initialize(transId, CrudServiceConstants.CRD_SERVICE_NAME, "", fromAppId, fromIp);
+ }
+
+ /**
+ * Logs the rest request.
+ */
+ public static void logRestRequest(Logger logger, Logger auditLogger, HttpServletRequest req, Response response) {
+ String respStatusString = "";
+ if (Response.Status.fromStatusCode(response.getStatus()) != null) {
+ respStatusString = Response.Status.fromStatusCode(response.getStatus()).toString();
+ }
+
+ // Generate error log
+ logger.info(CrudServiceMsgs.PROCESS_REST_REQUEST, req.getMethod(), req.getRequestURL().toString(),
+ req.getRemoteHost(), Integer.toString(response.getStatus()));
+
+ // Generate audit log.
+ auditLogger.info(CrudServiceMsgs.PROCESS_REST_REQUEST,
+ new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, response.getStatus())
+ .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, respStatusString),
+ (req != null) ? req.getMethod() : "Unknown", (req != null) ? req.getRequestURL().toString() : "Unknown",
+ (req != null) ? req.getRemoteHost() : "Unknown", Integer.toString(response.getStatus()) + " payload: "
+ + (response.getEntity() == null ? "" : response.getEntity().toString()));
+ MDC.clear();
+ }
+}
diff --git a/src/main/java/org/onap/crud/parser/CrudResponseBuilder.java b/src/main/java/org/onap/crud/parser/CrudResponseBuilder.java
new file mode 100644
index 0000000..62d1408
--- /dev/null
+++ b/src/main/java/org/onap/crud/parser/CrudResponseBuilder.java
@@ -0,0 +1,212 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.parser;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.core.Response.Status;
+
+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.schema.RelationshipSchemaLoader;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+public class CrudResponseBuilder {
+
+ private static final Gson gson = new GsonBuilder().create();
+
+ public static final String SOURCE = "source";
+ public static final String TARGET = "target";
+ public static final String URL_BASE = "services/inventory/";
+
+ public static String buildUpsertBulkResponse(HashMap<String, Vertex> vertices, HashMap<String, Edge> edges,
+ String version, BulkPayload incomingPayload) throws CrudException {
+
+ for (JsonElement e : incomingPayload.getObjects()) {
+ List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
+ e.getAsJsonObject().entrySet());
+
+ Map.Entry<String, JsonElement> item = entries.get(1);
+
+ Vertex responseVertex = vertices.get(item.getKey());
+ if (responseVertex != null) {
+ JsonObject v = gson.fromJson(buildUpsertVertexResponse(responseVertex, version), JsonObject.class);
+ item.setValue(v);
+ } else {
+ item.setValue(gson.fromJson("{}", JsonObject.class));
+ }
+
+ }
+ for (JsonElement e : incomingPayload.getRelationships()) {
+ List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
+ e.getAsJsonObject().entrySet());
+
+ Map.Entry<String, JsonElement> item = entries.get(1);
+
+ Edge responseEdge = edges.get(item.getKey());
+ if (responseEdge != null) {
+ JsonObject v = gson.fromJson(buildUpsertEdgeResponse(responseEdge, version), JsonObject.class);
+ item.setValue(v);
+ } else {
+ item.setValue(gson.fromJson("{}", JsonObject.class));
+ }
+
+ }
+ return incomingPayload.toJson();
+ }
+
+ public static String buildUpsertVertexResponse(Vertex vertex, String version) throws CrudException {
+ VertexPayload payload = new VertexPayload();
+ payload.setId(vertex.getId().get());
+ payload.setType(vertex.getType());
+ payload.setUrl(URL_BASE + version + "/" + vertex.getType() + "/" + vertex.getId().get());
+ JsonObject props = new JsonObject();
+ for (String key : vertex.getProperties().keySet()) {
+ addJsonProperperty(props, key, vertex.getProperties().get(key));
+ }
+ payload.setProperties(props);
+ return payload.toJson();
+ }
+
+ public static String buildUpsertEdgeResponse(Edge edge, String version) throws CrudException {
+ return buildGetEdgeResponse(edge, version);
+ }
+
+ public static String buildGetVertexResponse(Vertex vertex, List<Edge> edges, String version) throws CrudException {
+ VertexPayload vertexPayload = new VertexPayload();
+ vertexPayload.setId(vertex.getId().get());
+ vertexPayload.setType(vertex.getType());
+ vertexPayload.setUrl(URL_BASE + version + "/" + vertex.getType() + "/" + vertex.getId().get());
+ JsonObject props = new JsonObject();
+ for (String key : vertex.getProperties().keySet()) {
+ addJsonProperperty(props, key, vertex.getProperties().get(key));
+ }
+ vertexPayload.setProperties(props);
+ List<EdgePayload> inEdges = new ArrayList<EdgePayload>();
+ List<EdgePayload> outEdges = new ArrayList<EdgePayload>();
+ for (Edge e : edges) {
+ if (e.getTarget().getId().get().equals(vertex.getId().get())) {
+ EdgePayload inEdge = new EdgePayload();
+ inEdge.setId(e.getId().get());
+ inEdge.setType(e.getType());
+ inEdge.setUrl(URL_BASE + "relationships/" + RelationshipSchemaLoader.getLatestSchemaVersion() + "/"
+ + e.getType() + "/" + e.getId().get());
+ inEdge.setSource(URL_BASE + version + "/" + e.getSource().getType() + "/" + e.getSource().getId().get());
+
+ inEdges.add(inEdge);
+ } else if (e.getSource().getId().get().equals(vertex.getId().get())) {
+ EdgePayload outEdge = new EdgePayload();
+ outEdge.setId(e.getId().get());
+ outEdge.setType(e.getType());
+ outEdge.setUrl(URL_BASE + "relationships/" + RelationshipSchemaLoader.getLatestSchemaVersion() + "/"
+ + e.getType() + "/" + e.getId().get());
+ outEdge.setTarget(URL_BASE + version + "/" + e.getTarget().getType() + "/" + e.getTarget().getId().get());
+ outEdges.add(outEdge);
+ }
+ }
+
+ vertexPayload.setIn(inEdges);
+ vertexPayload.setOut(outEdges);
+
+ return vertexPayload.toJson();
+ }
+
+ public static String buildGetVerticesResponse(List<Vertex> items, String version) throws CrudException {
+
+ JsonArray arry = new JsonArray();
+ for (Vertex v : items) {
+ JsonObject item = new JsonObject();
+ item.addProperty("id", v.getId().get());
+ item.addProperty("type", v.getType());
+ item.addProperty("url", "services/inventory/" + version + "/" + v.getType() + "/" + v.getId().get());
+
+ arry.add(item);
+ }
+
+ return gson.toJson(arry);
+ }
+
+ public static String buildGetEdgeResponse(Edge edge, String version) throws CrudException {
+
+ EdgePayload payload = new EdgePayload();
+ payload.setId(edge.getId().get());
+ payload.setType(edge.getType());
+ payload.setUrl(URL_BASE + "relationships/" + version + "/" + edge.getType() + "/" + edge.getId().get());
+ payload.setSource(URL_BASE + version + "/" + edge.getSource().getType() + "/" + edge.getSource().getId().get());
+ payload.setTarget(URL_BASE + version + "/" + edge.getTarget().getType() + "/" + edge.getTarget().getId().get());
+
+ JsonObject props = new JsonObject();
+ for (String key : edge.getProperties().keySet()) {
+ addJsonProperperty(props, key, edge.getProperties().get(key));
+ }
+ payload.setProperties(props);
+ return payload.toJson();
+ }
+
+ public static String buildGetEdgesResponse(List<Edge> items, String version) throws CrudException {
+
+ JsonArray arry = new JsonArray();
+ for (Edge e : items) {
+ JsonObject item = new JsonObject();
+ item.addProperty("id", e.getId().get());
+ item.addProperty("type", e.getType());
+ item.addProperty("url", URL_BASE + "relationships/" + version + "/" + e.getType() + "/" + e.getId().get());
+ item.addProperty(SOURCE,
+ "services/inventory/" + version + "/" + e.getSource().getType() + "/" + e.getSource().getId().get());
+ item.addProperty(TARGET,
+ "services/inventory/" + version + "/" + e.getTarget().getType() + "/" + e.getTarget().getId().get());
+ arry.add(item);
+ }
+
+ return gson.toJson(arry);
+ }
+
+ private static void addJsonProperperty(JsonObject jsonObj, String key, Object value) {
+ if (value instanceof Integer) {
+ jsonObj.addProperty(key, (Integer) value);
+ } else if (value instanceof Boolean) {
+ jsonObj.addProperty(key, (Boolean) value);
+ } else if (value instanceof Double) {
+ jsonObj.addProperty(key, (Double) value);
+ } else if (value instanceof String) {
+ jsonObj.addProperty(key, (String) value);
+ } else {
+ jsonObj.addProperty(key, value.toString());
+ }
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/service/AaiResourceService.java b/src/main/java/org/onap/crud/service/AaiResourceService.java
new file mode 100644
index 0000000..2e4464d
--- /dev/null
+++ b/src/main/java/org/onap/crud/service/AaiResourceService.java
@@ -0,0 +1,533 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.service;
+
+import java.security.cert.X509Certificate;
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.serialization.db.EdgeProperty;
+import org.onap.aai.serialization.db.EdgeRule;
+import org.onap.aai.serialization.db.EdgeRules;
+import org.onap.aai.serialization.db.EdgeType;
+import org.openecomp.auth.Auth;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.crud.exception.CrudException;
+import org.onap.crud.logging.CrudServiceMsgs;
+import org.onap.crud.logging.LoggingUtil;
+import org.onap.crud.service.CrudRestService.Action;
+import org.onap.crud.util.CrudServiceConstants;
+import org.onap.schema.RelationshipSchemaLoader;
+import org.onap.schema.RelationshipSchemaValidator;
+import org.slf4j.MDC;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonPrimitive;
+
+
+/**
+ * This defines a set of REST endpoints which allow clients to create or update graph edges
+ * where the edge rules defined by the A&AI will be invoked to automatically populate the
+ * defined edge properties.
+ */
+public class AaiResourceService {
+
+ private String mediaType = MediaType.APPLICATION_JSON;
+ public static final String HTTP_PATCH_METHOD_OVERRIDE = "X-HTTP-Method-Override";
+
+ private Auth auth;
+ CrudGraphDataService crudGraphDataService;
+ Gson gson = new Gson();
+
+ private Logger logger = LoggerFactory.getInstance().getLogger(AaiResourceService.class.getName());
+ private Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(AaiResourceService.class.getName());
+
+ public AaiResourceService() {}
+
+ /**
+ * Creates a new instance of the AaiResourceService.
+ *
+ * @param crudGraphDataService - Service used for interacting with the graph.
+ *
+ * @throws Exception
+ */
+ public AaiResourceService(CrudGraphDataService crudGraphDataService) throws Exception {
+ this.crudGraphDataService = crudGraphDataService;
+ this.auth = new Auth(CrudServiceConstants.CRD_AUTH_FILE);
+ }
+
+ /**
+ * Perform any one-time initialization required when starting the service.
+ */
+ public void startup() {
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("AaiResourceService started!");
+ }
+ }
+
+
+ /**
+ * Creates a new relationship in the graph, automatically populating the edge
+ * properties based on the A&AI edge rules.
+ *
+ * @param content - Json structure describing the relationship to create.
+ * @param type - Relationship type supplied as a URI parameter.
+ * @param uri - Http request uri
+ * @param headers - Http request headers
+ * @param uriInfo - Http URI info field
+ * @param req - Http request structure.
+ *
+ * @return - Standard HTTP response.
+ */
+ @POST
+ @Path("/relationships/{type}/")
+ @Consumes({MediaType.APPLICATION_JSON})
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response createRelationship(String content,
+ @PathParam("type") String type,
+ @PathParam("uri") @Encoded String uri,
+ @Context HttpHeaders headers,
+ @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("Incoming request..." + content);
+ }
+
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+
+ // Extract the edge payload from the request.
+ EdgePayload payload = EdgePayload.fromJson(content);
+
+ // Do some basic validation on the payload.
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null) {
+ throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
+ }
+ if (payload.getType() != null && !payload.getType().equals(type)) {
+ throw new CrudException("Edge Type mismatch", Status.BAD_REQUEST);
+ }
+
+ // Apply the edge rules to our edge.
+ payload = applyEdgeRulesToPayload(payload);
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("Creating AAI edge using version " + RelationshipSchemaLoader.getLatestSchemaVersion() );
+ }
+
+ // Now, create our edge in the graph store.
+ String result = crudGraphDataService.addEdge(RelationshipSchemaLoader.getLatestSchemaVersion(), type, payload);
+ response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
+
+ } catch (CrudException e) {
+
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+
+ /**
+ * Creates a new relationship in the graph, automatically populating the edge
+ * properties based on the A&AI edge rules.
+ *
+ * @param content - Json structure describing the relationship to create.
+ * @param uri - Http request uri
+ * @param headers - Http request headers
+ * @param uriInfo - Http URI info field
+ * @param req - Http request structure.
+ *
+ * @return - Standard HTTP response.
+ *
+ */
+ @POST
+ @Path("/relationships/")
+ @Consumes({MediaType.APPLICATION_JSON})
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response createRelationship(String content,
+ @PathParam("uri") @Encoded String uri,
+ @Context HttpHeaders headers,
+ @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+
+ // Extract the edge payload from the request.
+ EdgePayload payload = EdgePayload.fromJson(content);
+
+ // Do some basic validation on the payload.
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null) {
+ throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
+ }
+ if (payload.getType() == null || payload.getType().isEmpty()) {
+ throw new CrudException("Missing Edge Type ", Status.BAD_REQUEST);
+ }
+
+ // Apply the edge rules to our edge.
+ payload = applyEdgeRulesToPayload(payload);
+
+ // Now, create our edge in the graph store.
+ String result = crudGraphDataService.addEdge(RelationshipSchemaLoader.getLatestSchemaVersion(), payload.getType(), payload);
+ response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
+
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content)
+ .type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+
+
+ /**
+ * Upserts a relationship into the graph, automatically populating the edge properties
+ * based on the A&AI edge rules. The behaviour is as follows:
+ * <p>
+ * <li>If no relationship with the supplied identifier already exists, then a new relationship
+ * is created with that id.<br>
+ * <li>If a relationship with the supplied id DOES exist, then it is replaced with the supplied
+ * content.
+ *
+ * @param content - Json structure describing the relationship to create.
+ * @param type - Relationship type supplied as a URI parameter.
+ * @param id - Edge identifier.
+ * @param uri - Http request uri
+ * @param headers - Http request headers
+ * @param uriInfo - Http URI info field
+ * @param req - Http request structure.
+ *
+ * @return - Standard HTTP response.
+ */
+ @PUT
+ @Path("/relationships/{type}/{id}")
+ @Consumes({MediaType.APPLICATION_JSON})
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response upsertEdge(String content,
+ @PathParam("type") String type,
+ @PathParam("id") String id,
+ @PathParam("uri") @Encoded String uri,
+ @Context HttpHeaders headers,
+ @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+
+ // Extract the edge payload from the request.
+ EdgePayload payload = EdgePayload.fromJson(content);
+
+ // Do some basic validation on the payload.
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null && !payload.getId().equals(id)) {
+ throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
+ }
+
+ // Apply the edge rules to our edge.
+ payload = applyEdgeRulesToPayload(payload);
+
+ String result;
+ if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null &&
+ headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
+ result = crudGraphDataService.patchEdge(RelationshipSchemaLoader.getLatestSchemaVersion(), id, type, payload);
+ } else {
+
+ result = crudGraphDataService.updateEdge(RelationshipSchemaLoader.getLatestSchemaVersion(), id, type, payload);
+ }
+
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+
+ } else {
+
+ response = Response.status(Status.FORBIDDEN).entity(content)
+ .type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+
+ /**
+ * Retrieves the properties defined in the edge rules for a relationship between the
+ * supplied vertex types.
+ *
+ * @param sourceVertexType - Type of source vertex for the relationship.
+ * @param targetVertexType - Type of target vertex for the relationship.
+ *
+ * @return - The defined properties for the relationship type.
+ *
+ * @throws CrudException
+ */
+ private Map<EdgeProperty, String> getEdgeRuleProperties(String sourceVertexType, String targetVertexType) throws CrudException {
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("Lookup db edge rules for " + sourceVertexType + " -> " + targetVertexType);
+ }
+
+ EdgeRules rules = EdgeRules.getInstance();
+ EdgeRule rule;
+ try {
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("Lookup by edge type TREE");
+ }
+
+ // We have no way of knowing in advance whether our relationship is considered to
+ // be a tree or cousing relationship, so try looking it up as a tree type first.
+ rule = rules.getEdgeRule(EdgeType.TREE, sourceVertexType, targetVertexType);
+
+ } catch (AAIException e) {
+ try {
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("Lookup by edge type COUSIN");
+ }
+
+ // If we are here, then our lookup by 'tree' type failed, so try looking it up
+ // as a 'cousin' relationship.
+ rule = rules.getEdgeRule(EdgeType.COUSIN, sourceVertexType, targetVertexType);
+
+ } catch (AAIException e1) {
+
+ // If we're here then we failed to find edge rules for this relationship. Time to
+ // give up...
+ throw new CrudException("No edge rules for " + sourceVertexType + " -> " + targetVertexType, Status.NOT_FOUND);
+ }
+ } catch (Exception e) {
+
+ throw new CrudException("General failure getting edge rule properties - " +
+ e.getMessage(), Status.INTERNAL_SERVER_ERROR);
+ }
+
+ return rule.getEdgeProperties();
+ }
+
+
+ /**
+ * This method takes an inbound edge request payload, looks up the edge rules for the
+ * sort of relationship defined in the payload, and automatically applies the defined
+ * edge properties to it.
+ *
+ * @param payload - The original edge request payload
+ *
+ * @return - An updated edge request payload, with the properties defined in the edge
+ * rules automatically populated.
+ *
+ * @throws CrudException
+ */
+ public EdgePayload applyEdgeRulesToPayload(EdgePayload payload) throws CrudException {
+
+ // Extract the types for both the source and target vertices.
+ String srcType = RelationshipSchemaValidator.vertexTypeFromUri(payload.getSource());
+ String tgtType = RelationshipSchemaValidator.vertexTypeFromUri(payload.getTarget());
+
+ // Now, get the default properties for this edge based on the edge rules definition...
+ Map<EdgeProperty, String> props = getEdgeRuleProperties(srcType, tgtType);
+
+ // ...and merge them with any custom properties provided in the request.
+ JsonElement mergedProperties = mergeProperties(payload.getProperties(), props);
+ payload.setProperties(mergedProperties);
+
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("Edge properties after applying rules for '" + srcType + " -> " + tgtType + "': " + mergedProperties);
+ }
+
+ return payload;
+ }
+
+
+ /**
+ * Given a set of edge properties extracted from an edge request payload and a set of properties
+ * taken from the db edge rules, this method merges them into one set of properties.
+ * <p>
+ * If the client has attempted to override the defined value for a property in the db edge rules
+ * then the request will be rejected as invalid.
+ *
+ * @param propertiesFromRequest - Set of properties from the edge request.
+ * @param propertyDefaults - Set of properties from the db edge rules.
+ *
+ * @return - A merged set of properties.
+ *
+ * @throws CrudException
+ */
+ public JsonElement mergeProperties(JsonElement propertiesFromRequest, Map<EdgeProperty, String> propertyDefaults) throws CrudException {
+
+ // Convert the properties from the edge payload into something we can
+ // manipulate.
+ Set<Map.Entry<String, JsonElement>> properties = new HashSet<Map.Entry<String, JsonElement>>();
+ properties.addAll(propertiesFromRequest.getAsJsonObject().entrySet());
+
+ Set<String> propertyKeys = new HashSet<String>();
+ for(Map.Entry<String, JsonElement> property : properties) {
+ propertyKeys.add(property.getKey());
+ }
+
+ // Now, merge in the properties specified in the Db Edge Rules.
+ for(EdgeProperty defProperty : propertyDefaults.keySet()) {
+
+ // If the edge rules property was explicitly specified by the
+ // client then we will reject the request...
+ if(!propertyKeys.contains(defProperty.toString())) {
+ properties.add(new AbstractMap.SimpleEntry<String, JsonElement>(defProperty.toString(),
+ (JsonElement)(new JsonPrimitive(propertyDefaults.get(defProperty)))));
+
+ } else {
+ throw new CrudException("Property " + defProperty + " defined in db edge rules can not be overriden by the client.",
+ Status.BAD_REQUEST);
+ }
+ }
+
+ Object[] propArray = properties.toArray();
+ StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ boolean first=true;
+ for(int i=0; i<propArray.length; i++) {
+
+ Map.Entry<String, JsonElement> entry = (Entry<String, JsonElement>) propArray[i];
+ if(!first) {
+ sb.append(",");
+ }
+ sb.append("\"").append(entry.getKey()).append("\"").append(":").append(entry.getValue());
+ first=false;
+ }
+ sb.append("}");
+
+ // We're done. Return the result as a JsonElement.
+ return gson.fromJson(sb.toString(), JsonElement.class);
+ }
+
+
+ /**
+ * Invokes authentication validation on an incoming HTTP request.
+ *
+ * @param req - The HTTP request.
+ * @param uri - HTTP URI
+ * @param content - Payload of the HTTP request.
+ * @param action - What HTTP action is being performed (GET/PUT/POST/PATCH/DELETE)
+ * @param authPolicyFunctionName - Policy function being invoked.
+ *
+ * @return true - if the request passes validation,
+ * false - otherwise.
+ */
+ protected boolean validateRequest(HttpServletRequest req,
+ String uri,
+ String content,
+ Action action,
+ String authPolicyFunctionName) {
+ try {
+ String cipherSuite = (String) req.getAttribute("javax.servlet.request.cipher_suite");
+ String authUser = null;
+ if (cipherSuite != null) {
+
+ X509Certificate[] certChain = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
+ X509Certificate clientCert = certChain[0];
+ X500Principal subjectDn = clientCert.getSubjectX500Principal();
+ authUser = subjectDn.toString();
+ }
+
+ return this.auth.validateRequest(authUser.toLowerCase(), action.toString() + ":" + authPolicyFunctionName);
+
+ } catch (Exception e) {
+ logResult(action, uri, e);
+ return false;
+ }
+ }
+
+ protected void logResult(Action op, String uri, Exception e) {
+
+ logger.error(CrudServiceMsgs.EXCEPTION_DURING_METHOD_CALL,
+ op.toString(),
+ uri,
+ e.getStackTrace().toString());
+
+ // Clear the MDC context so that no other transaction inadvertently
+ // uses our transaction id.
+ MDC.clear();
+ }
+}
diff --git a/src/main/java/org/onap/crud/service/BulkPayload.java b/src/main/java/org/onap/crud/service/BulkPayload.java
new file mode 100644
index 0000000..538d9c0
--- /dev/null
+++ b/src/main/java/org/onap/crud/service/BulkPayload.java
@@ -0,0 +1,124 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import org.onap.crud.exception.CrudException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.core.Response.Status;
+
+public class BulkPayload {
+ public enum OperationType {
+ CREATE, UPDATE, DELETE
+ }
+
+ private List<JsonElement> objects = new ArrayList<JsonElement>();
+ private List<JsonElement> relationships = new ArrayList<JsonElement>();
+
+ private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ public static BulkPayload fromJson(String payload) throws CrudException {
+ try {
+ if (payload == null || payload.isEmpty()) {
+ throw new CrudException("Invalid Json Payload", Status.BAD_REQUEST);
+ }
+ return gson.fromJson(payload, BulkPayload.class);
+ } catch (Exception ex) {
+ throw new CrudException("Invalid Json Payload", Status.BAD_REQUEST);
+ }
+ }
+
+ public List<JsonElement> getObjects() {
+ return objects;
+ }
+
+ public void setObjects(List<JsonElement> objects) {
+ this.objects = objects;
+ }
+
+ public List<JsonElement> getRelationships() {
+ return relationships;
+ }
+
+ public void setRelationships(List<JsonElement> relationships) {
+ this.relationships = relationships;
+ }
+
+ @Override
+ public String toString() {
+ return "BulkPayload [objects=" + objects + ", relationships=" + relationships + "]";
+ }
+
+ public static void main(String[] args) throws Exception {
+ BulkPayload p = new BulkPayload();
+ JsonObject root = new JsonObject();
+ JsonArray vertices = new JsonArray();
+ JsonObject v1 = new JsonObject();
+ JsonObject v2 = new JsonObject();
+ JsonObject prop = new JsonObject();
+
+ prop.addProperty("p1", "value1");
+ prop.addProperty("p2", "value2");
+ v1.add("v1", prop);
+ v2.add("v2", prop);
+
+ vertices.add(v1);
+ vertices.add(v2);
+
+ root.add("objects", vertices);
+
+ String s = "{\"objects\":[{\"v1\":{\"p1\":\"value1\",\"p2\":\"value2\"}},{\"v2\":{\"p1\":\"value1\",\"p2\":\"value2\"}}]}";
+
+ p = BulkPayload.fromJson(s);
+
+ List<JsonElement> po = p.getObjects();
+ List<String> ids = new ArrayList<String>();
+ for (JsonElement e : po) {
+ Set<Map.Entry<String, JsonElement>> entries = e.getAsJsonObject().entrySet();
+
+ for (Map.Entry<String, JsonElement> entry : entries) {
+ ids.add(entry.getKey());
+ }
+ }
+
+ System.out.println("root: " + root.toString());
+ System.out.println("payload ids: " + ids.toString());
+
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/onap/crud/service/CrudGraphDataService.java b/src/main/java/org/onap/crud/service/CrudGraphDataService.java
new file mode 100644
index 0000000..268e492
--- /dev/null
+++ b/src/main/java/org/onap/crud/service/CrudGraphDataService.java
@@ -0,0 +1,301 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.aaiutils.oxm.OxmModelLoader;
+import org.onap.aai.champcore.ChampGraph;
+import org.onap.crud.dao.GraphDao;
+import org.onap.crud.dao.champ.ChampDao;
+import org.onap.crud.entity.Edge;
+
+import org.onap.crud.entity.Vertex;
+import org.onap.crud.exception.CrudException;
+import org.onap.crud.parser.CrudResponseBuilder;
+import org.onap.schema.OxmModelValidator;
+import org.onap.schema.RelationshipSchemaLoader;
+import org.onap.schema.RelationshipSchemaValidator;
+
+import com.google.gson.JsonElement;
+
+public class CrudGraphDataService {
+
+ private GraphDao dao;
+
+ public CrudGraphDataService(ChampGraph graphImpl) throws CrudException {
+ this.dao = new ChampDao(graphImpl);
+
+ loadModels();
+ }
+
+ public CrudGraphDataService(GraphDao dao) throws CrudException {
+ this.dao = dao;
+
+ loadModels();
+ }
+
+ private void loadModels() throws CrudException {
+ // load the schemas
+ try {
+ OxmModelLoader.loadModels();
+ } catch (Exception e) {
+ throw new CrudException(e);
+ }
+ RelationshipSchemaLoader.loadModels();
+ }
+
+ public String addVertex(String version, String type, VertexPayload payload) throws CrudException {
+ Vertex vertex = OxmModelValidator.validateIncomingUpsertPayload(null, version, type, payload.getProperties());
+ return addVertex(version, vertex);
+ }
+
+ public String addBulk(String version, BulkPayload payload) throws CrudException {
+ HashMap<String, Vertex> vertices = new HashMap<String, Vertex>();
+ HashMap<String, Edge> edges = new HashMap<String, Edge>();
+ String txId = dao.openTransaction();
+ try {
+ // Handle vertices
+ for (JsonElement v : payload.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("add")
+ || opr.getValue().getAsString().equalsIgnoreCase("modify")) {
+ Vertex validatedVertex;
+ Vertex persistedVertex;
+ if (opr.getValue().getAsString().equalsIgnoreCase("add")) {
+ validatedVertex = OxmModelValidator.validateIncomingUpsertPayload(null, version, vertexPayload.getType(),
+ vertexPayload.getProperties());
+ // Call champDAO to add the vertex
+ persistedVertex = dao.addVertex(validatedVertex.getType(), validatedVertex.getProperties(), txId);
+ } else {
+ validatedVertex = OxmModelValidator.validateIncomingUpsertPayload(vertexPayload.getId(), version,
+ vertexPayload.getType(), vertexPayload.getProperties());
+ // Call champDAO to update the vertex
+ persistedVertex = dao.updateVertex(vertexPayload.getId(), validatedVertex.getType(),
+ validatedVertex.getProperties(), txId);
+ }
+
+ Vertex outgoingVertex = OxmModelValidator.validateOutgoingPayload(version, persistedVertex);
+
+ vertices.put(item.getKey(), outgoingVertex);
+
+ } else if (opr.getValue().getAsString().equalsIgnoreCase("delete")) {
+ dao.deleteVertex(vertexPayload.getId(),
+ OxmModelValidator.resolveCollectionType(version, vertexPayload.getType()), txId);
+ }
+
+ }
+ // Handle Edges
+ for (JsonElement v : payload.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("add")
+ || opr.getValue().getAsString().equalsIgnoreCase("modify")) {
+ Edge validatedEdge;
+ Edge persistedEdge;
+ if (opr.getValue().getAsString().equalsIgnoreCase("add")) {
+ // Fix the source/detination
+ if (edgePayload.getSource().startsWith("$")) {
+ Vertex source = vertices.get(edgePayload.getSource().substring(1));
+ if (source == null) {
+ throw new CrudException("Not able to find vertex: " + edgePayload.getSource().substring(1),
+ Status.INTERNAL_SERVER_ERROR);
+ }
+ edgePayload
+ .setSource("services/inventory/" + version + "/" + source.getType() + "/" + source.getId().get());
+ }
+ if (edgePayload.getTarget().startsWith("$")) {
+ Vertex target = vertices.get(edgePayload.getTarget().substring(1));
+ if (target == null) {
+ throw new CrudException("Not able to find vertex: " + edgePayload.getTarget().substring(1),
+ Status.INTERNAL_SERVER_ERROR);
+ }
+ edgePayload
+ .setTarget("services/inventory/" + version + "/" + target.getType() + "/" + target.getId().get());
+ }
+ validatedEdge = RelationshipSchemaValidator.validateIncomingAddPayload(version, edgePayload.getType(),
+ edgePayload);
+ persistedEdge = dao.addEdge(validatedEdge.getType(), validatedEdge.getSource(), validatedEdge.getTarget(),
+ validatedEdge.getProperties(), txId);
+ } else {
+ Edge edge = dao.getEdge(edgePayload.getId(), edgePayload.getType(), txId);
+ validatedEdge = RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, edgePayload);
+ persistedEdge = dao.updateEdge(edge, txId);
+ }
+
+ Edge outgoingEdge = RelationshipSchemaValidator.validateOutgoingPayload(version, persistedEdge);
+
+ edges.put(item.getKey(), outgoingEdge);
+
+ } else if (opr.getValue().getAsString().equalsIgnoreCase("delete")) {
+ RelationshipSchemaValidator.validateType(version, edgePayload.getType());
+ dao.deleteEdge(edgePayload.getId(), edgePayload.getType(), txId);
+ }
+
+ }
+ // close champ TX
+ dao.commitTransaction(txId);
+ } catch (CrudException ex) {
+ dao.rollbackTransaction(txId);
+ throw ex;
+ } catch (Exception ex) {
+ dao.rollbackTransaction(txId);
+ throw ex;
+ } finally {
+ if (dao.transactionExists(txId)) {
+ dao.rollbackTransaction(txId);
+ }
+ }
+
+ return CrudResponseBuilder.buildUpsertBulkResponse(vertices, edges, version, payload);
+ }
+
+ private String addVertex(String version, Vertex vertex) throws CrudException {
+ Vertex addedVertex = dao.addVertex(vertex.getType(), vertex.getProperties());
+ return CrudResponseBuilder
+ .buildUpsertVertexResponse(OxmModelValidator.validateOutgoingPayload(version, addedVertex), version);
+ }
+
+ public String addEdge(String version, String type, EdgePayload payload) throws CrudException {
+ Edge edge = RelationshipSchemaValidator.validateIncomingAddPayload(version, type, payload);
+ return addEdge(version, edge);
+ }
+
+ private String addEdge(String version, Edge edge) throws CrudException {
+ Edge addedEdge = dao.addEdge(edge.getType(), edge.getSource(), edge.getTarget(), edge.getProperties());
+ return CrudResponseBuilder
+ .buildUpsertEdgeResponse(RelationshipSchemaValidator.validateOutgoingPayload(version, addedEdge), version);
+ }
+
+ public String getEdge(String version, String id, String type) throws CrudException {
+ RelationshipSchemaValidator.validateType(version, type);
+ Edge edge = dao.getEdge(id, type);
+
+ return CrudResponseBuilder.buildGetEdgeResponse(RelationshipSchemaValidator.validateOutgoingPayload(version, edge),
+ version);
+ }
+
+ public String getEdges(String version, String type, Map<String, String> filter) throws CrudException {
+ RelationshipSchemaValidator.validateType(version, type);
+ List<Edge> items = dao.getEdges(type, RelationshipSchemaValidator.resolveCollectionfilter(version, type, filter));
+ return CrudResponseBuilder.buildGetEdgesResponse(items, version);
+ }
+
+ public String updateVertex(String version, String id, String type, VertexPayload payload) throws CrudException {
+ Vertex vertex = OxmModelValidator.validateIncomingUpsertPayload(id, version, type, payload.getProperties());
+ return updateVertex(version, vertex);
+
+ }
+
+ private String updateVertex(String version, Vertex vertex) throws CrudException {
+ Vertex updatedVertex = dao.updateVertex(vertex.getId().get(), vertex.getType(), vertex.getProperties());
+ return CrudResponseBuilder
+ .buildUpsertVertexResponse(OxmModelValidator.validateOutgoingPayload(version, updatedVertex), version);
+ }
+
+ public String patchVertex(String version, String id, String type, VertexPayload payload) throws CrudException {
+ Vertex existingVertex = dao.getVertex(id, OxmModelValidator.resolveCollectionType(version, type));
+ Vertex vertex = OxmModelValidator.validateIncomingPatchPayload(id, version, type, payload.getProperties(),
+ existingVertex);
+ return updateVertex(version, vertex);
+
+ }
+
+ public String deleteVertex(String version, String id, String type) throws CrudException {
+ type = OxmModelValidator.resolveCollectionType(version, type);
+ dao.deleteVertex(id, type);
+ return "";
+
+ }
+
+ public String deleteEdge(String version, String id, String type) throws CrudException {
+ RelationshipSchemaValidator.validateType(version, type);
+ dao.deleteEdge(id, type);
+ return "";
+
+ }
+
+ public String updateEdge(String version, String id, String type, EdgePayload payload) throws CrudException {
+ Edge edge = dao.getEdge(id, type);
+ Edge validatedEdge = RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, payload);
+ return updateEdge(version, validatedEdge);
+
+ }
+
+ private String updateEdge(String version, Edge edge) throws CrudException {
+ Edge updatedEdge = dao.updateEdge(edge);
+ return CrudResponseBuilder
+ .buildUpsertEdgeResponse(RelationshipSchemaValidator.validateOutgoingPayload(version, updatedEdge), version);
+ }
+
+ public String patchEdge(String version, String id, String type, EdgePayload payload) throws CrudException {
+ Edge edge = dao.getEdge(id, type);
+ Edge patchedEdge = RelationshipSchemaValidator.validateIncomingPatchPayload(edge, version, payload);
+ return updateEdge(version, patchedEdge);
+
+ }
+
+ public Vertex getVertex(String id) throws CrudException {
+ return dao.getVertex(id);
+ }
+
+ public String getVertex(String version, String id, String type) throws CrudException {
+ type = OxmModelValidator.resolveCollectionType(version, type);
+ Vertex vertex = dao.getVertex(id, type);
+ List<Edge> edges = dao.getVertexEdges(id);
+ return CrudResponseBuilder.buildGetVertexResponse(OxmModelValidator.validateOutgoingPayload(version, vertex), edges,
+ version);
+ }
+
+ public String getVertices(String version, String type, Map<String, String> filter) throws CrudException {
+ type = OxmModelValidator.resolveCollectionType(version, type);
+ List<Vertex> items = dao.getVertices(type, OxmModelValidator.resolveCollectionfilter(version, type, filter));
+ return CrudResponseBuilder.buildGetVerticesResponse(items, version);
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/service/CrudRestService.java b/src/main/java/org/onap/crud/service/CrudRestService.java
new file mode 100644
index 0000000..da792b5
--- /dev/null
+++ b/src/main/java/org/onap/crud/service/CrudRestService.java
@@ -0,0 +1,784 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.service;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.ext.PATCH;
+import org.openecomp.auth.Auth;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.crud.exception.CrudException;
+import org.onap.crud.logging.CrudServiceMsgs;
+import org.onap.crud.logging.LoggingUtil;
+import org.onap.crud.util.CrudServiceConstants;
+import org.slf4j.MDC;
+
+import com.google.gson.JsonElement;
+
+public class CrudRestService {
+
+ private CrudGraphDataService crudGraphDataService;
+ Logger logger = LoggerFactory.getInstance().getLogger(CrudRestService.class.getName());
+ Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(CrudRestService.class.getName());
+ private Auth auth;
+
+ private String mediaType = MediaType.APPLICATION_JSON;
+ public static final String HTTP_PATCH_METHOD_OVERRIDE = "X-HTTP-Method-Override";
+
+ public CrudRestService(CrudGraphDataService crudGraphDataService) throws Exception {
+ this.crudGraphDataService = crudGraphDataService;
+ this.auth = new Auth(CrudServiceConstants.CRD_AUTH_FILE);
+ }
+
+ public enum Action {
+ POST, GET, PUT, DELETE, PATCH
+ }
+
+ ;
+
+ public void startup() {
+
+ }
+
+ @GET
+ @Path("/{version}/{type}/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ String result = crudGraphDataService.getVertex(version, id, type);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @GET
+ @Path("/{version}/{type}/")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getVertices(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+ if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ Map<String, String> filter = new HashMap<String, String>();
+ for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
+ filter.put(e.getKey(), e.getValue().get(0));
+ }
+
+ try {
+ String result = crudGraphDataService.getVertices(version, type, filter);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @GET
+ @Path("/relationships/{version}/{type}/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+
+ String result = crudGraphDataService.getEdge(version, id, type);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @GET
+ @Path("/relationships/{version}/{type}/")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getEdges(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ Map<String, String> filter = new HashMap<String, String>();
+ for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
+ filter.put(e.getKey(), e.getValue().get(0));
+ }
+
+ try {
+ String result = crudGraphDataService.getEdges(version, type, filter);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @PUT
+ @Path("/relationships/{version}/{type}/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response updateEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ EdgePayload payload = EdgePayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null && !payload.getId().equals(id)) {
+ throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
+ }
+ String result;
+
+ if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null
+ && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
+ result = crudGraphDataService.patchEdge(version, id, type, payload);
+ } else {
+
+ result = crudGraphDataService.updateEdge(version, id, type, payload);
+ }
+
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @PATCH
+ @Path("/relationships/{version}/{type}/{id}")
+ @Consumes({ "application/merge-patch+json" })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response patchEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+ if (validateRequest(req, uri, content, Action.PATCH, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ EdgePayload payload = EdgePayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null && !payload.getId().equals(id)) {
+ throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
+ }
+
+ String result = crudGraphDataService.patchEdge(version, id, type, payload);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @PUT
+ @Path("/{version}/{type}/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response updateVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ VertexPayload payload = VertexPayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null && !payload.getId().equals(id)) {
+ throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
+ }
+ String result;
+ if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null
+ && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
+ result = crudGraphDataService.patchVertex(version, id, type, payload);
+ } else {
+
+ result = crudGraphDataService.updateVertex(version, id, type, payload);
+ }
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @PATCH
+ @Path("/{version}/{type}/{id}")
+ @Consumes({ "application/merge-patch+json" })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response patchVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.PATCH, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+ try {
+ VertexPayload payload = VertexPayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null && !payload.getId().equals(id)) {
+ throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
+ }
+
+ String result = crudGraphDataService.patchVertex(version, id, type, payload);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @POST
+ @Path("/{version}/{type}/")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response addVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ VertexPayload payload = VertexPayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null) {
+ throw new CrudException("ID specified , use Http PUT to update Vertex", Status.BAD_REQUEST);
+ }
+
+ if (payload.getType() != null && !payload.getType().equals(type)) {
+ throw new CrudException("Vertex Type mismatch", Status.BAD_REQUEST);
+ }
+
+ String result = crudGraphDataService.addVertex(version, type, payload);
+ response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ private void validateBulkPayload(BulkPayload payload) throws CrudException {
+ List<String> vertices = new ArrayList<String>();
+ List<String> edges = new ArrayList<String>();
+
+ for (JsonElement v : payload.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);
+
+ if (vertices.contains(item.getKey())) {
+ throw new CrudException("duplicate vertex in payload: " + item.getKey(), Status.BAD_REQUEST);
+ }
+ VertexPayload vertexPayload = VertexPayload.fromJson(item.getValue().getAsJsonObject().toString());
+ if (vertexPayload.getType() == null) {
+ throw new CrudException("Vertex Type cannot be null for: " + item.getKey(), Status.BAD_REQUEST);
+ }
+
+ if (!opr.getKey().equalsIgnoreCase("operation")) {
+ throw new CrudException("operation missing in item: " + item.getKey(), Status.BAD_REQUEST);
+ }
+
+ if (!opr.getValue().getAsString().equalsIgnoreCase("add")
+ && !opr.getValue().getAsString().equalsIgnoreCase("modify")
+ && !opr.getValue().getAsString().equalsIgnoreCase("delete")) {
+ throw new CrudException("Invalid operation at item: " + item.getKey(), Status.BAD_REQUEST);
+ }
+ // check if ID is populate for modify/delete operation
+ if ((opr.getValue().getAsString().equalsIgnoreCase("modify")
+ || opr.getValue().getAsString().equalsIgnoreCase("delete")) && (vertexPayload.getId() == null)) {
+
+ throw new CrudException("Mising ID at item: " + item.getKey(), Status.BAD_REQUEST);
+
+ }
+
+ vertices.add(item.getKey());
+ }
+
+ for (JsonElement v : payload.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);
+
+ if (edges.contains(item.getKey())) {
+ throw new CrudException("duplicate Edge in payload: " + item.getKey(), Status.BAD_REQUEST);
+ }
+
+ EdgePayload edgePayload = EdgePayload.fromJson(item.getValue().getAsJsonObject().toString());
+
+ if (edgePayload.getType() == null) {
+ throw new CrudException("Edge Type cannot be null for: " + item.getKey(), Status.BAD_REQUEST);
+ }
+
+ if (!opr.getKey().equalsIgnoreCase("operation")) {
+ throw new CrudException("operation missing in item: " + item.getKey(), Status.BAD_REQUEST);
+ }
+
+ if (!opr.getValue().getAsString().equalsIgnoreCase("add")
+ && !opr.getValue().getAsString().equalsIgnoreCase("modify")
+ && !opr.getValue().getAsString().equalsIgnoreCase("delete")) {
+ throw new CrudException("Invalid operation at item: " + item.getKey(), Status.BAD_REQUEST);
+ }
+ // check if ID is populate for modify/delete operation
+ if ((edgePayload.getId() == null) && (opr.getValue().getAsString().equalsIgnoreCase("modify")
+ || opr.getValue().getAsString().equalsIgnoreCase("delete"))) {
+
+ throw new CrudException("Mising ID at item: " + item.getKey(), Status.BAD_REQUEST);
+
+ }
+ if (opr.getValue().getAsString().equalsIgnoreCase("add")) {
+ if (edgePayload.getSource() == null || edgePayload.getTarget() == null) {
+ throw new CrudException("Source/Target cannot be null for edge: " + item.getKey(), Status.BAD_REQUEST);
+ }
+ if (edgePayload.getSource().startsWith("$") && !vertices.contains(edgePayload.getSource().substring(1))) {
+ throw new CrudException(
+ "Source Vertex " + edgePayload.getSource().substring(1) + " not found for Edge: " + item.getKey(),
+ Status.BAD_REQUEST);
+ }
+
+ if (edgePayload.getTarget().startsWith("$") && !vertices.contains(edgePayload.getTarget().substring(1))) {
+ throw new CrudException(
+ "Target Vertex " + edgePayload.getSource().substring(1) + " not found for Edge: " + item.getKey(),
+ Status.BAD_REQUEST);
+ }
+ }
+ edges.add(item.getKey());
+
+ }
+
+ }
+
+ @POST
+ @Path("/{version}/bulk/")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response addBulk(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ BulkPayload payload = BulkPayload.fromJson(content);
+ if ((payload.getObjects() == null && payload.getRelationships() == null)
+ || (payload.getObjects() != null && payload.getObjects().isEmpty() && payload.getRelationships() != null
+ && payload.getRelationships().isEmpty())) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+
+ validateBulkPayload(payload);
+ String result = crudGraphDataService.addBulk(version, payload);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @POST
+ @Path("/{version}/")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response addVertex(String content, @PathParam("version") String version, @PathParam("uri") @Encoded String uri,
+ @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+ try {
+
+ VertexPayload payload = VertexPayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null) {
+ throw new CrudException("ID specified , use Http PUT to update Vertex", Status.BAD_REQUEST);
+ }
+
+ if (payload.getType() == null || payload.getType().isEmpty()) {
+ throw new CrudException("Missing Vertex Type ", Status.BAD_REQUEST);
+ }
+ String result = crudGraphDataService.addVertex(version, payload.getType(), payload);
+ response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @POST
+ @Path("/relationships/{version}/{type}/")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response addEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ EdgePayload payload = EdgePayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null) {
+ throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
+ }
+
+ if (payload.getType() != null && !payload.getType().equals(type)) {
+ throw new CrudException("Edge Type mismatch", Status.BAD_REQUEST);
+ }
+ String result = crudGraphDataService.addEdge(version, type, payload);
+ response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @POST
+ @Path("/relationships/{version}/")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response addEdge(String content, @PathParam("version") String version, @PathParam("uri") @Encoded String uri,
+ @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ EdgePayload payload = EdgePayload.fromJson(content);
+ if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
+ throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
+ }
+ if (payload.getId() != null) {
+ throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
+ }
+
+ if (payload.getType() == null || payload.getType().isEmpty()) {
+ throw new CrudException("Missing Edge Type ", Status.BAD_REQUEST);
+ }
+ String result = crudGraphDataService.addEdge(version, payload.getType(), payload);
+
+ response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @DELETE
+ @Path("/{version}/{type}/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response deleteVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+
+ if (validateRequest(req, uri, content, Action.DELETE, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ String result = crudGraphDataService.deleteVertex(version, id, type);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ @DELETE
+ @Path("/relationships/{version}/{type}/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response deleteEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
+ @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo, @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+
+ logger.debug("Incoming request..." + content);
+ Response response = null;
+ if (validateRequest(req, uri, content, Action.DELETE, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
+
+ try {
+ String result = crudGraphDataService.deleteEdge(version, id, type);
+ response = Response.status(Status.OK).entity(result).type(mediaType).build();
+ } catch (CrudException ce) {
+ response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
+ } catch (Exception e) {
+ response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ } else {
+ response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ return response;
+ }
+
+ protected boolean validateRequest(HttpServletRequest req, String uri, String content, Action action,
+ String authPolicyFunctionName) {
+ try {
+ String cipherSuite = (String) req.getAttribute("javax.servlet.request.cipher_suite");
+ String authUser = null;
+ if (cipherSuite != null) {
+ X509Certificate[] certChain = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
+ X509Certificate clientCert = certChain[0];
+ X500Principal subjectDn = clientCert.getSubjectX500Principal();
+ authUser = subjectDn.toString();
+ }
+ return this.auth.validateRequest(authUser.toLowerCase(), action.toString() + ":" + authPolicyFunctionName);
+ } catch (Exception e) {
+ logResult(action, uri, e);
+ return false;
+ }
+ }
+
+ void logResult(Action op, String uri, Exception e) {
+
+ logger.error(CrudServiceMsgs.EXCEPTION_DURING_METHOD_CALL, op.toString(), uri, e.getStackTrace().toString());
+
+ // Clear the MDC context so that no other transaction inadvertently
+ // uses our transaction id.
+ MDC.clear();
+ }
+}
diff --git a/src/main/java/org/onap/crud/service/EdgePayload.java b/src/main/java/org/onap/crud/service/EdgePayload.java
new file mode 100644
index 0000000..dc25497
--- /dev/null
+++ b/src/main/java/org/onap/crud/service/EdgePayload.java
@@ -0,0 +1,115 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+
+import org.onap.crud.exception.CrudException;
+
+import javax.ws.rs.core.Response.Status;
+
+public class EdgePayload {
+
+ private String id;
+ private String type;
+ private String url;
+ private String source;
+ private String target;
+ private JsonElement properties;
+
+ private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
+
+ @Override
+ public String toString() {
+ return "EdgePayload [id=" + id + ", type=" + type + ", url=" + url + ", source="
+ + source + ", target=" + target + ", properties=" + properties + "]";
+ }
+
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ public static EdgePayload fromJson(String payload) throws CrudException {
+ try {
+ if (payload == null || payload.isEmpty()) {
+ throw new CrudException("Invalid Json Payload", Status.BAD_REQUEST);
+ }
+ return gson.fromJson(payload, EdgePayload.class);
+ } catch (Exception ex) {
+ throw new CrudException("Invalid Json Payload", Status.BAD_REQUEST);
+ }
+ }
+
+ 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 String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ 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;
+ }
+
+ public JsonElement getProperties() {
+ return properties;
+ }
+
+ public void setProperties(JsonElement properties) {
+ this.properties = properties;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/onap/crud/service/JaxrsEchoService.java b/src/main/java/org/onap/crud/service/JaxrsEchoService.java
new file mode 100644
index 0000000..cdea726
--- /dev/null
+++ b/src/main/java/org/onap/crud/service/JaxrsEchoService.java
@@ -0,0 +1,63 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.service;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.crud.logging.LoggingUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+
+public class JaxrsEchoService {
+
+ private static Logger logger = LoggerFactory.getInstance()
+ .getLogger(JaxrsEchoService.class.getName());
+ private static Logger auditLogger = LoggerFactory.getInstance()
+ .getAuditLogger(JaxrsEchoService.class.getName());
+
+ @GET
+ @Path("echo/{input}")
+ @Produces("text/plain")
+ public String ping(@PathParam("input") String input,
+ @Context HttpHeaders headers,
+ @Context UriInfo info,
+ @Context HttpServletRequest req) {
+
+ LoggingUtil.initMdcContext(req, headers);
+ LoggingUtil.logRestRequest(logger, auditLogger, req, Response.status(Status.OK)
+ .entity("OK").build());
+
+ return "Hello, " + input + ".";
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/onap/crud/service/VertexPayload.java b/src/main/java/org/onap/crud/service/VertexPayload.java
new file mode 100644
index 0000000..4529d70
--- /dev/null
+++ b/src/main/java/org/onap/crud/service/VertexPayload.java
@@ -0,0 +1,117 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+
+import org.onap.crud.exception.CrudException;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+
+public class VertexPayload {
+
+ private String id;
+ private String type;
+ private String url;
+ private JsonElement properties;
+ private List<EdgePayload> in = new ArrayList<EdgePayload>();
+ private List<EdgePayload> out = new ArrayList<EdgePayload>();
+
+ private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
+ public String toJson() {
+ return gson.toJson(this);
+ }
+
+ public static VertexPayload fromJson(String payload) throws CrudException {
+ try {
+ if (payload == null || payload.isEmpty()) {
+ throw new CrudException("Invalid Json Payload", Status.BAD_REQUEST);
+ }
+ return gson.fromJson(payload, VertexPayload.class);
+ } catch (Exception ex) {
+ throw new CrudException("Invalid Json Payload", Status.BAD_REQUEST);
+ }
+ }
+
+ 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 String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public JsonElement getProperties() {
+ return properties;
+ }
+
+ public void setProperties(JsonElement properties) {
+ this.properties = properties;
+ }
+
+ public List<EdgePayload> getIn() {
+ return in;
+ }
+
+ public void setIn(List<EdgePayload> in) {
+ this.in = in;
+ }
+
+ public List<EdgePayload> getOut() {
+ return out;
+ }
+
+ public void setOut(List<EdgePayload> out) {
+ this.out = out;
+ }
+
+
+ @Override
+ public String toString() {
+ return "VertexPayload [id=" + id + ", type=" + type + ", url=" + url + ", properties="
+ + properties + ", in=" + in + ", out=" + out + "]";
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/onap/crud/util/CrudJaxbTransformation.java b/src/main/java/org/onap/crud/util/CrudJaxbTransformation.java
new file mode 100644
index 0000000..05afea2
--- /dev/null
+++ b/src/main/java/org/onap/crud/util/CrudJaxbTransformation.java
@@ -0,0 +1,92 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.util;
+
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.jaxb.JAXBMarshaller;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.eclipse.persistence.jaxb.UnmarshallerProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import javax.ws.rs.core.MediaType;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+
+public class CrudJaxbTransformation {
+ /**
+ * Marshal a dynamic entity into a string.
+ *
+ * @param entity the dynamic entity
+ * @param jaxbContext the dynamic jaxb context
+ * @return the marshaled entity
+ * @throws RouterException on error
+ */
+ public static String marshal(MediaType mediaType, final DynamicEntity entity,
+ final DynamicJAXBContext jaxbContext) throws JAXBException {
+
+ final JAXBMarshaller marshaller = jaxbContext.createMarshaller();
+ marshaller.setProperty(JAXBMarshaller.JAXB_FORMATTED_OUTPUT, false);
+
+ if (MediaType.APPLICATION_JSON_TYPE.isCompatible(mediaType)) {
+ marshaller.setProperty("eclipselink.media-type", "application/json");
+ marshaller.setProperty("eclipselink.json.include-root", false);
+ marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE);
+ }
+
+ final StringWriter writer = new StringWriter();
+ marshaller.marshal(entity, writer);
+ return writer.toString();
+
+ }
+
+ /**
+ * @param type
+ * @param json
+ * @param mediaType
+ * @return
+ * @throws JAXBException
+ * @throws Exception
+ */
+ public static Object unmarshal(String javaClass, String content, MediaType mediaType,
+ final DynamicJAXBContext jaxbContext) throws JAXBException {
+ Object clazz = null;
+ Unmarshaller unmarshaller = null;
+
+ clazz = jaxbContext.newDynamicEntity(javaClass);
+
+ unmarshaller = jaxbContext.createUnmarshaller();
+ if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
+ unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
+ }
+
+ return unmarshaller.unmarshal(new StreamSource(new StringReader(content)),
+ clazz.getClass()).getValue();
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/util/CrudProperties.java b/src/main/java/org/onap/crud/util/CrudProperties.java
new file mode 100644
index 0000000..b029dd1
--- /dev/null
+++ b/src/main/java/org/onap/crud/util/CrudProperties.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+public class CrudProperties {
+
+ private static Properties properties;
+
+ static {
+ properties = new Properties();
+ File file = new File(CrudServiceConstants.CRD_CONFIG_FILE);
+ try {
+ properties.load(new FileInputStream(file));
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String get(String key) {
+ return properties.getProperty(key);
+ }
+
+ public static String get(String key, String defaultValue) {
+ return properties.getProperty(key, defaultValue);
+ }
+
+ public static void put(String key, String value) {
+ properties.setProperty(key, value);
+ FileOutputStream fileOut = null;
+ try {
+ fileOut = new FileOutputStream(new File(CrudServiceConstants.CRD_CONFIG_FILE));
+ properties.store(fileOut, "Added property: " + key);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+
+ try {
+ fileOut.close();
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ }
+
+
+}
diff --git a/src/main/java/org/onap/crud/util/CrudServiceConstants.java b/src/main/java/org/onap/crud/util/CrudServiceConstants.java
new file mode 100644
index 0000000..0d07707
--- /dev/null
+++ b/src/main/java/org/onap/crud/util/CrudServiceConstants.java
@@ -0,0 +1,54 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.util;
+
+public class CrudServiceConstants {
+ public static final String CRD_SERVICE_NAME = "Crud-Service";
+
+ public static final String CRD_FILESEP = (System.getProperty("file.separator") == null) ? "/"
+ : System.getProperty("file.separator");
+
+ public static final String CRD_SPECIFIC_CONFIG = System.getProperty("CONFIG_HOME") + CRD_FILESEP;
+
+ public static final String CRD_HOME_MODEL = CRD_SPECIFIC_CONFIG + "model" + CRD_FILESEP;
+ public static final String CRD_HOME_AUTH = CRD_SPECIFIC_CONFIG + "auth" + CRD_FILESEP;
+
+ public static final String CRD_GRAPH_HOST = "crud.graph.host";
+ public static final String CRD_GRAPH_PORT = "crud.graph.port";
+ public static final String CRD_GRAPH_NAME = "crud.graph.name";
+ public static final String CRD_STORAGE_BACKEND_DB = "crud.storage.backend.db";
+ public static final String CRD_HBASE_ZNODE_PARENT
+ = "crud.storage.hbase.ext.zookeeper.znode.parent";
+
+ public static final String CRD_CONFIG_FILE = CRD_SPECIFIC_CONFIG + "crud-api.properties";
+ public static final String CRD_AUTH_FILE = CRD_HOME_AUTH + "crud_policy.json";
+ public static final String CRD_CHAMPION_AUTH_FILE = CRD_HOME_AUTH + "champion-cert.p12";
+
+ public static final String CRD_AUTH_POLICY_NAME = "crud";
+
+ public static final String CRD_EVENT_STREAM_HOSTS = "event.stream.hosts";
+
+
+
+}
diff --git a/src/main/java/org/onap/crud/util/CrudServiceUtil.java b/src/main/java/org/onap/crud/util/CrudServiceUtil.java
new file mode 100644
index 0000000..49b0317
--- /dev/null
+++ b/src/main/java/org/onap/crud/util/CrudServiceUtil.java
@@ -0,0 +1,63 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.util;
+
+import org.onap.crud.exception.CrudException;
+
+import javax.ws.rs.core.Response.Status;
+
+public class CrudServiceUtil {
+
+
+ public static Object validateFieldType(String value, Class clazz) throws CrudException {
+ try {
+ if (clazz.isAssignableFrom(Integer.class)) {
+ return Integer.parseInt(value);
+ } else if (clazz.isAssignableFrom(Long.class)) {
+ return Long.parseLong(value);
+ } else if (clazz.isAssignableFrom(Float.class)) {
+ return Float.parseFloat(value);
+ } else if (clazz.isAssignableFrom(Double.class)) {
+ return Double.parseDouble(value);
+ } else if (clazz.isAssignableFrom(Boolean.class)) {
+
+ // If the value is an IN/OUT direction, this gets seen as a boolean, so
+ // check for that first.
+ if (value.equals("OUT") || value.equals("IN")) {
+ return value;
+ }
+
+ if (!value.equals("true") && !value.equals("false")) {
+ throw new CrudException("Invalid propertry value: " + value, Status.BAD_REQUEST);
+ }
+ return Boolean.parseBoolean(value);
+ } else {
+ return value;
+ }
+ } catch (Exception e) {
+ throw new CrudException("Invalid property value: " + value, Status.BAD_REQUEST);
+ }
+ }
+
+}
diff --git a/src/main/java/org/onap/crud/util/FileWatcher.java b/src/main/java/org/onap/crud/util/FileWatcher.java
new file mode 100644
index 0000000..711fa08
--- /dev/null
+++ b/src/main/java/org/onap/crud/util/FileWatcher.java
@@ -0,0 +1,48 @@
+/**
+ * ============LICENSE_START=======================================================
+ * Gizmo
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.crud.util;
+
+import java.io.File;
+import java.util.TimerTask;
+
+public abstract class FileWatcher extends TimerTask {
+ private long timeStamp;
+ private File file;
+
+ public FileWatcher(File file) {
+ this.file = file;
+ this.timeStamp = file.lastModified();
+ }
+
+ public final void run() {
+ long timeStamp = file.lastModified();
+
+ if ((timeStamp - this.timeStamp) > 500) {
+ this.timeStamp = timeStamp;
+ onChange(file);
+ }
+ }
+
+ protected abstract void onChange(File file);
+} \ No newline at end of file