summaryrefslogtreecommitdiffstats
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/openecomp/crud/dao/GraphDao.java138
-rw-r--r--src/main/java/org/openecomp/crud/dao/champ/ChampDao.java750
-rw-r--r--src/main/java/org/openecomp/crud/entity/Edge.java130
-rw-r--r--src/main/java/org/openecomp/crud/entity/Vertex.java102
-rw-r--r--src/main/java/org/openecomp/crud/event/GraphEvent.java235
-rw-r--r--src/main/java/org/openecomp/crud/event/GraphEventEdge.java212
-rw-r--r--src/main/java/org/openecomp/crud/event/GraphEventVertex.java181
-rw-r--r--src/main/java/org/openecomp/crud/exception/CrudException.java62
-rw-r--r--src/main/java/org/openecomp/crud/logging/CrudServiceMsgs.java128
-rw-r--r--src/main/java/org/openecomp/crud/logging/LoggingUtil.java88
-rw-r--r--src/main/java/org/openecomp/crud/parser/CrudResponseBuilder.java185
-rw-r--r--src/main/java/org/openecomp/crud/service/CrudGraphDataService.java209
-rw-r--r--src/main/java/org/openecomp/crud/service/CrudRestService.java686
-rw-r--r--src/main/java/org/openecomp/crud/service/EdgePayload.java115
-rw-r--r--src/main/java/org/openecomp/crud/service/JaxrsEchoService.java63
-rw-r--r--src/main/java/org/openecomp/crud/service/VertexPayload.java117
-rw-r--r--src/main/java/org/openecomp/crud/util/CrudJaxbTransformation.java92
-rw-r--r--src/main/java/org/openecomp/crud/util/CrudProperties.java77
-rw-r--r--src/main/java/org/openecomp/crud/util/CrudServiceConstants.java53
-rw-r--r--src/main/java/org/openecomp/crud/util/CrudServiceUtil.java56
-rw-r--r--src/main/java/org/openecomp/crud/util/FileWatcher.java48
-rw-r--r--src/main/java/org/openecomp/schema/OxmModelLoader.java168
-rw-r--r--src/main/java/org/openecomp/schema/OxmModelValidator.java325
-rw-r--r--src/main/java/org/openecomp/schema/RelationshipSchema.java138
-rw-r--r--src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java158
-rw-r--r--src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java341
26 files changed, 4857 insertions, 0 deletions
diff --git a/src/main/java/org/openecomp/crud/dao/GraphDao.java b/src/main/java/org/openecomp/crud/dao/GraphDao.java
new file mode 100644
index 0000000..20b568c
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/dao/GraphDao.java
@@ -0,0 +1,138 @@
+/**
+ * ============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.openecomp.crud.dao;
+
+import org.openecomp.crud.entity.Edge;
+import org.openecomp.crud.entity.Vertex;
+import org.openecomp.crud.exception.CrudException;
+
+import java.util.List;
+import java.util.Map;
+
+public interface GraphDao {
+
+ 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;
+}
diff --git a/src/main/java/org/openecomp/crud/dao/champ/ChampDao.java b/src/main/java/org/openecomp/crud/dao/champ/ChampDao.java
new file mode 100644
index 0000000..ff0a332
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/dao/champ/ChampDao.java
@@ -0,0 +1,750 @@
+/**
+ * ============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.openecomp.crud.dao.champ;
+
+import org.openecomp.aai.champ.ChampAPI;
+import org.openecomp.aai.champ.ChampGraph;
+import org.openecomp.aai.champ.exceptions.ChampMarshallingException;
+import org.openecomp.aai.champ.exceptions.ChampObjectNotExistsException;
+import org.openecomp.aai.champ.exceptions.ChampRelationshipNotExistsException;
+import org.openecomp.aai.champ.exceptions.ChampSchemaViolationException;
+import org.openecomp.aai.champ.exceptions.ChampUnmarshallingException;
+import org.openecomp.aai.champ.graph.impl.TitanChampGraphImpl;
+import org.openecomp.aai.champ.model.ChampObject;
+import org.openecomp.aai.champ.model.ChampRelationship;
+import org.openecomp.aai.champ.model.fluent.object.ObjectBuildOrPropertiesStep;
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.crud.dao.GraphDao;
+import org.openecomp.crud.entity.Edge;
+import org.openecomp.crud.entity.Vertex;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.logging.CrudServiceMsgs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+
+/**
+ * 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";
+
+
+ public static final String DEFAULT_GRAPH_NAME = "default_graph";
+
+ /**
+ * Set of configuration properties for the DAI.
+ */
+ private Properties daoConfig;
+
+ /**
+ * 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 config - Set of configuration properties to be applied to this instance
+ * of the DAO.
+ */
+ public ChampDao(Properties config) {
+
+ // Store the configuration properties.
+ daoConfig = config;
+
+ // Apply the configuration to the DAO.
+ configure();
+
+ }
+
+
+ @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.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName())!=null && retrievedVertex.get().getProperties()
+ .get(org.openecomp.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 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);
+ }
+ }
+
+
+ @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.openecomp.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 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.openecomp.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);
+ }
+
+ }
+
+
+ @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.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
+
+
+ Stream<ChampObject> retrievedVertices = champApi.queryObjects(filter);
+
+ 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 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 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 = champApi.queryRelationships(filter);
+ // 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 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 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 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.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
+ ? relationship.getSource().getType()
+ : relationship.getSource().getProperties()
+ .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()));
+ edgeBuilder.target(vertexFromChampObject(relationship.getTarget(),
+ relationship.getTarget().getProperties()
+ .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
+ ? relationship.getTarget().getType()
+ : relationship.getTarget().getProperties()
+ .get(org.openecomp.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 all one-time configuration operations which are required when creating
+ * a new instance of the DAO.
+ */
+ private void configure() {
+
+ // Instantiate the Champ library API.
+ try {
+
+ // Determine which back end we are using.
+ switch (getBackendTypeFromConfig()) {
+
+ case IN_MEMORY:
+
+ logger.info(CrudServiceMsgs.INSTANTIATE_GRAPH_DAO,
+ "In Memory",
+ daoConfig.getProperty(CONFIG_GRAPH_NAME, DEFAULT_GRAPH_NAME),
+ "Not applicable");
+
+ champApi = ChampGraph.Factory.newInstance(ChampGraph.Type.IN_MEMORY,
+ daoConfig.getProperty(CONFIG_GRAPH_NAME, DEFAULT_GRAPH_NAME));
+
+ break;
+
+ case TITAN:
+ try {
+ String db = daoConfig.getProperty(CONFIG_STORAGE_BACKEND_DB);
+ Short graphIdSuffix = (short) new Random().nextInt(Short.MAX_VALUE);
+ logger.info(CrudServiceMsgs.TITAN_GRAPH_INFO, GRAPH_UNQ_INSTANCE_ID_SUFFIX
+ + ": = " + graphIdSuffix);
+ if (db.equalsIgnoreCase(STORAGE_CASSANDRA_DB)) {
+ logger.info(CrudServiceMsgs.INSTANTIATE_GRAPH_DAO, "Titan with cassandra backend",
+ daoConfig.getProperty(CONFIG_GRAPH_NAME, DEFAULT_GRAPH_NAME),
+ daoConfig.getProperty(CONFIG_STORAGE_HOSTNAMES));
+
+ TitanChampGraphImpl.Builder champApiBuilder =
+ new TitanChampGraphImpl.Builder(daoConfig.getProperty(CONFIG_GRAPH_NAME,
+ DEFAULT_GRAPH_NAME))
+ .property("storage.backend", "cassandrathrift")
+ .property(GRAPH_UNQ_INSTANCE_ID_SUFFIX, graphIdSuffix)
+ .property("storage.hostname", daoConfig.get(CONFIG_STORAGE_HOSTNAMES));
+
+ if (daoConfig.containsKey(CONFIG_EVENT_STREAM_PUBLISHER)) {
+ champApiBuilder.property("champ.event.stream.publisher",
+ daoConfig.get(CONFIG_EVENT_STREAM_PUBLISHER));
+ }
+
+ if (daoConfig.containsKey(CONFIG_EVENT_STREAM_NUM_PUBLISHERS)) {
+ champApiBuilder.property("champ.event.stream.publisher-pool-size",
+ daoConfig.get(CONFIG_EVENT_STREAM_NUM_PUBLISHERS));
+ }
+
+ champApi = champApiBuilder.build();
+
+ } else if (db.equalsIgnoreCase(STORAGE_HBASE_DB)) {
+
+ logger.info(CrudServiceMsgs.INSTANTIATE_GRAPH_DAO, "Titan with Hbase backend",
+ daoConfig.getProperty(CONFIG_GRAPH_NAME, DEFAULT_GRAPH_NAME),
+ daoConfig.getProperty(CONFIG_STORAGE_HOSTNAMES));
+ TitanChampGraphImpl.Builder champApiBuilder =
+ new TitanChampGraphImpl.Builder(daoConfig
+ .getProperty(CONFIG_GRAPH_NAME, DEFAULT_GRAPH_NAME))
+ .property("storage.backend", "hbase")
+ .property("storage.hbase.ext.zookeeper.znode.parent",
+ daoConfig.get(CONFIG_HBASE_ZNODE_PARENT))
+ .property("storage.port", daoConfig.get(CONFIG_STORAGE_PORT))
+ .property(GRAPH_UNQ_INSTANCE_ID_SUFFIX, graphIdSuffix)
+ .property("storage.hostname", daoConfig.get(CONFIG_STORAGE_HOSTNAMES));
+
+ if (daoConfig.containsKey(CONFIG_EVENT_STREAM_PUBLISHER)) {
+ champApiBuilder.property("champ.event.stream.publisher",
+ daoConfig.get(CONFIG_EVENT_STREAM_PUBLISHER));
+ }
+
+ if (daoConfig.containsKey(CONFIG_EVENT_STREAM_NUM_PUBLISHERS)) {
+ champApiBuilder.property("champ.event.stream.publisher-pool-size",
+ daoConfig.get(CONFIG_EVENT_STREAM_NUM_PUBLISHERS));
+ }
+ champApi = champApiBuilder.build();
+ } else {
+ logger.error(CrudServiceMsgs.INVALID_GRAPH_BACKEND,
+ daoConfig.getProperty(CONFIG_STORAGE_BACKEND_DB));
+ }
+
+ } catch (com.thinkaurelius.titan.core.TitanException e) {
+
+ logger.error(CrudServiceMsgs.INSTANTIATE_GRAPH_BACKEND_ERR, "Titan", e.getMessage());
+ }
+
+
+ break;
+
+ default:
+ logger.error(CrudServiceMsgs.INVALID_GRAPH_BACKEND,
+ daoConfig.getProperty(CONFIG_STORAGE_BACKEND));
+ break;
+ }
+
+ } catch (CrudException e) {
+ logger.error(CrudServiceMsgs.INSTANTIATE_GRAPH_BACKEND_ERR,
+ daoConfig.getProperty(CONFIG_STORAGE_BACKEND), e.getMessage());
+ }
+ }
+
+
+ /**
+ * 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();
+ }
+ }
+
+
+ /**
+ * This helper function converts the 'graph back end type' config parameter into the
+ * corresponding {@link ChampAPI.Type}.
+ *
+ * @return - A {@link ChampAPI.Type}
+ * @throws CrudException
+ */
+ private ChampGraph.Type getBackendTypeFromConfig() throws CrudException {
+
+ // Get the back end type from the DAO's configuration properties.
+ String backend = daoConfig.getProperty(CONFIG_STORAGE_BACKEND, "in-memory");
+
+ // Now, find the appropriate ChampAPI type and return it.
+ if (backend.equals("in-memory")) {
+ return ChampGraph.Type.IN_MEMORY;
+ } else if (backend.equals("titan")) {
+ return ChampGraph.Type.TITAN;
+ }
+
+ // If we are here, then whatever was in the config properties didn't match to a supported
+ // back end type, so just throw an exception and let the caller figure it out.
+ throw new CrudException("Invalid graph backend type '" + backend + "' specified.",
+ javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ }
+
+
+}
diff --git a/src/main/java/org/openecomp/crud/entity/Edge.java b/src/main/java/org/openecomp/crud/entity/Edge.java
new file mode 100644
index 0000000..803511f
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/entity/Edge.java
@@ -0,0 +1,130 @@
+/**
+ * ============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.openecomp.crud.entity;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class Edge {
+ private static final Gson gson = new GsonBuilder().create();
+
+ 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 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/openecomp/crud/entity/Vertex.java b/src/main/java/org/openecomp/crud/entity/Vertex.java
new file mode 100644
index 0000000..1b0b97d
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/entity/Vertex.java
@@ -0,0 +1,102 @@
+/**
+ * ============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.openecomp.crud.entity;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class Vertex {
+ private static final Gson gson = new GsonBuilder().create();
+
+ 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);
+ }
+
+ @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/openecomp/crud/event/GraphEvent.java b/src/main/java/org/openecomp/crud/event/GraphEvent.java
new file mode 100644
index 0000000..392bf2d
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.crud.event;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.annotations.SerializedName;
+
+import org.openecomp.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/openecomp/crud/event/GraphEventEdge.java b/src/main/java/org/openecomp/crud/event/GraphEventEdge.java
new file mode 100644
index 0000000..aaf9b72
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.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.openecomp.crud.entity.Edge;
+import org.openecomp.crud.entity.Vertex;
+import org.openecomp.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/openecomp/crud/event/GraphEventVertex.java b/src/main/java/org/openecomp/crud/event/GraphEventVertex.java
new file mode 100644
index 0000000..7fde12a
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.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.openecomp.crud.entity.Vertex;
+import org.openecomp.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/openecomp/crud/exception/CrudException.java b/src/main/java/org/openecomp/crud/exception/CrudException.java
new file mode 100644
index 0000000..2911070
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.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/openecomp/crud/logging/CrudServiceMsgs.java b/src/main/java/org/openecomp/crud/logging/CrudServiceMsgs.java
new file mode 100644
index 0000000..71fb14b
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/logging/CrudServiceMsgs.java
@@ -0,0 +1,128 @@
+/**
+ * ============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.openecomp.crud.logging;
+
+import com.att.eelf.i18n.EELFResourceManager;
+
+import org.openecomp.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,
+
+ /**
+ * 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,
+
+ /**
+ * Instantiate data access layer for graph data store type: {0} graph: {1} using hosts: {2}
+ *
+ * <p>Arguments:
+ * {0} = Graph data store technology type
+ * {1} = Graph name
+ * {2} = Hosts list
+ */
+ INSTANTIATE_GRAPH_DAO,
+
+ /**
+ * Stopping ChampDAO...
+ *
+ * <p>Arguments:
+ */
+ STOPPING_CHAMP_DAO,
+
+ /**
+ * Unsupported graph database {0} specified.
+ *
+ * <p>Arguments:
+ * {0} = Graph database back end.
+ */
+ INVALID_GRAPH_BACKEND,
+
+ /**
+ * Failure instantiating {0} graph database backend. Cause: {1}
+ *
+ * <p>Arguments:
+ * {0} - Graph database type.
+ * {1} - Failure cause.
+ */
+ INSTANTIATE_GRAPH_BACKEND_ERR,
+
+ /**
+ * Failure instantiating CRUD Rest Service. Cause: {0}
+ *
+ * <p>Arguments:
+ * {0} - Failure cause.
+ */
+ INSTANTIATE_AUTH_ERR,
+
+ /**
+ * Any info log related to titan graph
+ *
+ * <p>Arguments:
+ * {0} - Info.
+ */
+ TITAN_GRAPH_INFO,
+
+ /**
+ * 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/openecomp/crud/logging/LoggingUtil.java b/src/main/java/org/openecomp/crud/logging/LoggingUtil.java
new file mode 100644
index 0000000..aaa250a
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/logging/LoggingUtil.java
@@ -0,0 +1,88 @@
+/**
+ * ============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.openecomp.crud.logging;
+
+import org.openecomp.cl.api.LogFields;
+import org.openecomp.cl.api.LogLine;
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.mdc.MdcContext;
+import org.openecomp.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()) + " error: " + (response.getEntity() == null ? ""
+ : response.getEntity().toString()));
+ MDC.clear();
+ }
+}
diff --git a/src/main/java/org/openecomp/crud/parser/CrudResponseBuilder.java b/src/main/java/org/openecomp/crud/parser/CrudResponseBuilder.java
new file mode 100644
index 0000000..1a84322
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/parser/CrudResponseBuilder.java
@@ -0,0 +1,185 @@
+/**
+ * ============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.openecomp.crud.parser;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+import org.openecomp.crud.entity.Edge;
+import org.openecomp.crud.entity.Vertex;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.service.EdgePayload;
+import org.openecomp.crud.service.VertexPayload;
+import org.openecomp.schema.RelationshipSchemaLoader;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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 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/openecomp/crud/service/CrudGraphDataService.java b/src/main/java/org/openecomp/crud/service/CrudGraphDataService.java
new file mode 100644
index 0000000..ce60c3c
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/service/CrudGraphDataService.java
@@ -0,0 +1,209 @@
+/**
+ * ============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.openecomp.crud.service;
+
+import com.att.ecomp.event.api.EventPublisher;
+
+import org.openecomp.crud.dao.GraphDao;
+import org.openecomp.crud.dao.champ.ChampDao;
+import org.openecomp.crud.entity.Edge;
+import org.openecomp.crud.entity.Vertex;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.parser.CrudResponseBuilder;
+import org.openecomp.crud.util.CrudProperties;
+import org.openecomp.crud.util.CrudServiceConstants;
+import org.openecomp.schema.OxmModelLoader;
+import org.openecomp.schema.OxmModelValidator;
+import org.openecomp.schema.RelationshipSchemaLoader;
+import org.openecomp.schema.RelationshipSchemaValidator;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class CrudGraphDataService {
+
+ private GraphDao dao;
+
+ public CrudGraphDataService(EventPublisher champEventPublisher) throws CrudException {
+
+ // Configure the GraphDao and wire it
+ Properties champProperties = new Properties();
+ champProperties.put(ChampDao.CONFIG_STORAGE_BACKEND, "titan");
+ champProperties.put(ChampDao.CONFIG_STORAGE_BACKEND_DB,
+ CrudProperties.get(CrudServiceConstants.CRD_STORAGE_BACKEND_DB, "hbase"));
+ champProperties.put(ChampDao.CONFIG_STORAGE_HOSTNAMES,
+ CrudProperties.get(CrudServiceConstants.CRD_GRAPH_HOST));
+ champProperties.put(ChampDao.CONFIG_STORAGE_PORT,
+ CrudProperties.get(CrudServiceConstants.CRD_GRAPH_PORT, "2181"));
+ champProperties.put(ChampDao.CONFIG_HBASE_ZNODE_PARENT,
+ CrudProperties.get(CrudServiceConstants.CRD_HBASE_ZNODE_PARENT, "/hbase-unsecure"));
+
+ if (CrudProperties.get("crud.graph.name") != null) {
+ champProperties.put(ChampDao.CONFIG_GRAPH_NAME, CrudProperties.get("crud.graph.name"));
+ }
+
+ if (champEventPublisher != null) {
+ champProperties.put(ChampDao.CONFIG_EVENT_STREAM_PUBLISHER, champEventPublisher);
+ }
+
+ if (CrudProperties.get(ChampDao.CONFIG_EVENT_STREAM_NUM_PUBLISHERS) != null) {
+ champProperties.put(ChampDao.CONFIG_EVENT_STREAM_NUM_PUBLISHERS,
+ Integer.parseInt(CrudProperties.get(ChampDao.CONFIG_EVENT_STREAM_NUM_PUBLISHERS)));
+ }
+
+ ChampDao champDao = new ChampDao(champProperties);
+
+ this.dao = champDao;
+
+ //load the schemas
+ OxmModelLoader.loadModels();
+ 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);
+ }
+
+ 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 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/openecomp/crud/service/CrudRestService.java b/src/main/java/org/openecomp/crud/service/CrudRestService.java
new file mode 100644
index 0000000..09193ad
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/service/CrudRestService.java
@@ -0,0 +1,686 @@
+/**
+ * ============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.openecomp.crud.service;
+
+import org.apache.cxf.jaxrs.ext.PATCH;
+import org.openecomp.auth.Auth;
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.logging.CrudServiceMsgs;
+import org.openecomp.crud.logging.LoggingUtil;
+import org.openecomp.crud.util.CrudServiceConstants;
+import org.slf4j.MDC;
+
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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;
+
+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;
+ }
+
+ @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/openecomp/crud/service/EdgePayload.java b/src/main/java/org/openecomp/crud/service/EdgePayload.java
new file mode 100644
index 0000000..d098d16
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.crud.service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+
+import org.openecomp.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/openecomp/crud/service/JaxrsEchoService.java b/src/main/java/org/openecomp/crud/service/JaxrsEchoService.java
new file mode 100644
index 0000000..0edd316
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.crud.service;
+
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.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/openecomp/crud/service/VertexPayload.java b/src/main/java/org/openecomp/crud/service/VertexPayload.java
new file mode 100644
index 0000000..ed79002
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.crud.service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+
+import org.openecomp.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/openecomp/crud/util/CrudJaxbTransformation.java b/src/main/java/org/openecomp/crud/util/CrudJaxbTransformation.java
new file mode 100644
index 0000000..c1a1e18
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.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/openecomp/crud/util/CrudProperties.java b/src/main/java/org/openecomp/crud/util/CrudProperties.java
new file mode 100644
index 0000000..69b2e16
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.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/openecomp/crud/util/CrudServiceConstants.java b/src/main/java/org/openecomp/crud/util/CrudServiceConstants.java
new file mode 100644
index 0000000..9543e2d
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/util/CrudServiceConstants.java
@@ -0,0 +1,53 @@
+/**
+ * ============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.openecomp.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_AUTH_POLICY_NAME = "crud";
+
+ public static final String CRD_EVENT_STREAM_HOSTS = "event.stream.hosts";
+
+
+
+}
diff --git a/src/main/java/org/openecomp/crud/util/CrudServiceUtil.java b/src/main/java/org/openecomp/crud/util/CrudServiceUtil.java
new file mode 100644
index 0000000..25e3de6
--- /dev/null
+++ b/src/main/java/org/openecomp/crud/util/CrudServiceUtil.java
@@ -0,0 +1,56 @@
+/**
+ * ============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.openecomp.crud.util;
+
+import org.openecomp.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 (!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/openecomp/crud/util/FileWatcher.java b/src/main/java/org/openecomp/crud/util/FileWatcher.java
new file mode 100644
index 0000000..8c7cbc1
--- /dev/null
+++ b/src/main/java/org/openecomp/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.openecomp.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
diff --git a/src/main/java/org/openecomp/schema/OxmModelLoader.java b/src/main/java/org/openecomp/schema/OxmModelLoader.java
new file mode 100644
index 0000000..4ef77a2
--- /dev/null
+++ b/src/main/java/org/openecomp/schema/OxmModelLoader.java
@@ -0,0 +1,168 @@
+/**
+ * ============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.openecomp.schema;
+
+import org.eclipse.persistence.jaxb.JAXBContextProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.logging.CrudServiceMsgs;
+import org.openecomp.crud.util.CrudServiceConstants;
+import org.openecomp.crud.util.FileWatcher;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.bind.JAXBException;
+
+
+public class OxmModelLoader {
+
+ private static Map<String, DynamicJAXBContext> versionContextMap
+ = new ConcurrentHashMap<String, DynamicJAXBContext>();
+ private static Map<String, Timer> timers = new ConcurrentHashMap<String, Timer>();
+
+ final static Pattern p = Pattern.compile("aai_oxm_(.*).xml");
+
+ private static org.openecomp.cl.api.Logger logger = LoggerFactory.getInstance()
+ .getLogger(OxmModelLoader.class.getName());
+
+ public synchronized static void loadModels() throws CrudException {
+ ClassLoader cl = OxmModelLoader.class.getClassLoader();
+ ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
+ Resource[] resources;
+ try {
+ resources = resolver.getResources("classpath*:/oxm/aai_oxm*.xml");
+ } catch (IOException ex) {
+ logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, ex.getMessage());
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+
+ if (resources.length == 0) {
+ logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, "No OXM schema files found on classpath");
+ throw new CrudException("Failed to load schema", Status.NOT_FOUND);
+ }
+
+ for (Resource resource : resources) {
+ Matcher matcher = p.matcher(resource.getFilename());
+
+ if (matcher.matches()) {
+ try {
+ OxmModelLoader.loadModel(matcher.group(1), resource);
+ } catch (Exception e) {
+ logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, "Failed to load " + resource.getFilename()
+ + ": " + e.getMessage());
+ throw new CrudException("Failed to load schema", Status.NOT_FOUND);
+ }
+ }
+ }
+ }
+
+ private static void addtimer(String version, File file) {
+ TimerTask task = null;
+ task = new FileWatcher(
+ file) {
+ protected void onChange(File file) {
+ // here we implement the onChange
+ logger.info(CrudServiceMsgs.OXM_FILE_CHANGED, file.getName());
+
+ try {
+ OxmModelLoader.loadModel(version, file);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+ };
+
+ if (!timers.containsKey(version)) {
+ Timer timer = new Timer("oxm-" + version);
+ timer.schedule(task, new Date(), 10000);
+ timers.put(version, timer);
+
+ }
+ }
+
+ private synchronized static void loadModel(String version, File file)
+ throws JAXBException, IOException {
+ InputStream inputStream = new FileInputStream(file);
+ loadModel(version, file.getName(), inputStream);
+ addtimer(version, file);
+ }
+
+ private synchronized static void loadModel(String version, Resource resource)
+ throws JAXBException, IOException {
+ InputStream inputStream = resource.getInputStream();
+ loadModel(version, resource.getFilename(), inputStream);
+ }
+
+ private synchronized static void loadModel(String version, String resourceName,
+ InputStream inputStream)
+ throws JAXBException, IOException {
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, inputStream);
+ final DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory
+ .createContextFromOXM(Thread.currentThread().getContextClassLoader(), properties);
+ versionContextMap.put(version, jaxbContext);
+ logger.info(CrudServiceMsgs.LOADED_OXM_FILE, resourceName);
+ }
+
+ public static DynamicJAXBContext getContextForVersion(String version) throws CrudException {
+ if (versionContextMap == null || versionContextMap.isEmpty()) {
+ loadModels();
+ } else if (!versionContextMap.containsKey(version)) {
+ try {
+ loadModel(version, new File(CrudServiceConstants.CRD_HOME_MODEL + "aai_oxm_"
+ + version + ".xml"));
+ } catch (Exception e) {
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+ }
+
+ return versionContextMap.get(version);
+ }
+
+ public static Map<String, DynamicJAXBContext> getVersionContextMap() {
+ return versionContextMap;
+ }
+
+ public static void setVersionContextMap(Map<String, DynamicJAXBContext> versionContextMap) {
+ OxmModelLoader.versionContextMap = versionContextMap;
+ }
+
+}
diff --git a/src/main/java/org/openecomp/schema/OxmModelValidator.java b/src/main/java/org/openecomp/schema/OxmModelValidator.java
new file mode 100644
index 0000000..45a2597
--- /dev/null
+++ b/src/main/java/org/openecomp/schema/OxmModelValidator.java
@@ -0,0 +1,325 @@
+/**
+ * ============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.openecomp.schema;
+
+import com.google.common.base.CaseFormat;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.eclipse.persistence.oxm.XMLField;
+import org.openecomp.crud.entity.Vertex;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.util.CrudServiceUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.ws.rs.core.Response.Status;
+
+public class OxmModelValidator {
+ public enum Metadata {
+ NODE_TYPE("aai-node-type"),
+ URI("aai-uri"),
+ CREATED_TS("aai-created-ts"),
+ SOT("source-of-truth"),
+ LAST_MOD_SOT("last-mod-source-of-truth");
+
+ private final String propName;
+
+ Metadata(String propName) {
+ this.propName = propName;
+ }
+
+ public String propertyName() {
+ return propName;
+ }
+
+ public static boolean isProperty(String property) {
+ for (Metadata meta : Metadata.values()) {
+ if (meta.propName.equals(property)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+
+ public static Map<String, Object> resolveCollectionfilter(String version, String type,
+ Map<String, String> filter)
+ throws CrudException {
+
+ DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version);
+
+ Map<String, Object> result = new HashMap<String, Object>();
+ if (jaxbContext == null) {
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+ final DynamicType modelObjectType = jaxbContext.getDynamicType(CaseFormat.LOWER_CAMEL
+ .to(CaseFormat.UPPER_CAMEL,
+ CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type)));
+
+ for (String key : filter.keySet()) {
+ String keyJavaName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, key);
+ if (modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName) != null) {
+ try {
+ DatabaseMapping mapping = modelObjectType.getDescriptor()
+ .getMappingForAttributeName(keyJavaName);
+ Object value = CrudServiceUtil.validateFieldType(filter.get(key),
+ mapping.getField().getType());
+ result.put(key, value);
+ } catch (Exception ex) {
+ // Skip any exceptions thrown while validating the filter
+ // key value
+ continue;
+ }
+ }
+ }
+
+ return result;
+
+ }
+
+ public static String resolveCollectionType(String version, String type) throws CrudException {
+
+ DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version);
+
+ if (jaxbContext == null) {
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+ // Determine if the Object part is a collection type in the model
+ // definition
+ final DynamicType modelObjectType = jaxbContext.getDynamicType(CaseFormat.LOWER_CAMEL
+ .to(CaseFormat.UPPER_CAMEL,
+ CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type)));
+
+ if (modelObjectType == null) {
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+
+ if (modelObjectType.getDescriptor().getMappings().size() == 1
+ && modelObjectType.getDescriptor().getMappings().get(0).isCollectionMapping()) {
+ String childJavaObjectName = modelObjectType.getDescriptor().getMappings()
+ .get(0).getAttributeName();
+ childJavaObjectName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, childJavaObjectName);
+ final DynamicType childObjectType = jaxbContext.getDynamicType(childJavaObjectName);
+ if (childObjectType == null) {
+ // Should not happen as child object is defined in oxm model
+ // itself
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+ return childObjectType.getDescriptor().getTableName();
+ } else {
+ return modelObjectType.getDescriptor().getTableName();
+ }
+
+ }
+
+
+ public static Vertex validateIncomingUpsertPayload(String id, String version, String type,
+ JsonElement properties)
+ throws CrudException {
+
+ try {
+ type = resolveCollectionType(version, type);
+ DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version);
+ String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,
+ CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type));
+
+ final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass);
+
+ Set<Map.Entry<String, JsonElement>> payloadEntriesSet = properties.getAsJsonObject()
+ .entrySet();
+
+ //loop through input to validate against schema
+ for (Map.Entry<String, JsonElement> entry : payloadEntriesSet) {
+ String keyJavaName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, entry.getKey());
+
+ // check for valid field
+ if (modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName) == null) {
+ throw new CrudException("Invalid field: " + entry.getKey(), Status.BAD_REQUEST);
+ }
+
+ }
+
+ Map<String, JsonElement> entriesMap = new HashMap<String, JsonElement>();
+ for (Map.Entry<String, JsonElement> entry : payloadEntriesSet) {
+ entriesMap.put(entry.getKey(), entry.getValue());
+ }
+
+ Vertex.Builder modelVertexBuilder = new Vertex.Builder(type);
+ if (id != null) {
+ modelVertexBuilder.id(id);
+ }
+ for (DatabaseMapping mapping : modelObjectType.getDescriptor().getMappings()) {
+ if (mapping.isAbstractDirectMapping()) {
+ DatabaseField field = mapping.getField();
+ String defaultValue = mapping.getProperties().get("defaultValue") == null ? ""
+ : mapping.getProperties().get("defaultValue").toString();
+
+ String keyName = field.getName().substring(0, field.getName().indexOf("/"));
+
+ if (((XMLField) field).isRequired() && !entriesMap.containsKey(keyName)
+ && !defaultValue.isEmpty()) {
+ modelVertexBuilder.property(keyName,
+ CrudServiceUtil.validateFieldType(defaultValue, field.getType()));
+ }
+ // if schema field is required and not set then reject
+ if (((XMLField) field).isRequired() && !entriesMap.containsKey(keyName)
+ && defaultValue.isEmpty()) {
+ throw new CrudException("Missing required field: " + keyName, Status.BAD_REQUEST);
+ }
+ // If invalid field then reject
+ if (entriesMap.containsKey(keyName)) {
+ Object value = CrudServiceUtil.validateFieldType(entriesMap.get(keyName)
+ .getAsString(), field.getType());
+ modelVertexBuilder.property(keyName, value);
+ }
+
+ // Set defaults
+ if (!defaultValue.isEmpty() && !entriesMap.containsKey(keyName)) {
+ modelVertexBuilder.property(keyName,
+ CrudServiceUtil.validateFieldType(defaultValue, field.getType()));
+ }
+ }
+ }
+
+ return modelVertexBuilder.build();
+ } catch (Exception e) {
+ throw new CrudException(e.getMessage(), Status.BAD_REQUEST);
+ }
+ }
+
+ public static Vertex validateIncomingPatchPayload(String id, String version, String type,
+ JsonElement properties, Vertex existingVertex)
+ throws CrudException {
+
+ try {
+ type = resolveCollectionType(version, type);
+ DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version);
+ String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,
+ CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type));
+
+ final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass);
+
+ Set<Map.Entry<String, JsonElement>> payloadEntriesSet = properties.getAsJsonObject()
+ .entrySet();
+
+ // Loop through the payload properties and merge with existing
+ // vertex props
+ for (Map.Entry<String, JsonElement> entry : payloadEntriesSet) {
+
+ String keyJavaName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, entry.getKey());
+
+ // check for valid field
+ if (modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName) == null) {
+ throw new CrudException("Invalid field: " + entry.getKey(), Status.BAD_REQUEST);
+ }
+
+ DatabaseField field = modelObjectType.getDescriptor()
+ .getMappingForAttributeName(keyJavaName).getField();
+ String defaultValue = modelObjectType.getDescriptor()
+ .getMappingForAttributeName(keyJavaName)
+ .getProperties().get("defaultValue") == null ? ""
+ : modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName)
+ .getProperties().get("defaultValue").toString();
+
+ // check if mandatory field is not set to null
+ if (((XMLField) field).isRequired() && entry.getValue() instanceof JsonNull
+ && !defaultValue.isEmpty()) {
+ existingVertex.getProperties().put(entry.getKey(),
+ CrudServiceUtil.validateFieldType(defaultValue, field.getType()));
+ } else if (((XMLField) field).isRequired() && entry.getValue() instanceof JsonNull
+ && defaultValue.isEmpty()) {
+ throw new CrudException("Mandatory field: " + entry.getKey()
+ + " can't be set to null",
+ Status.BAD_REQUEST);
+ } else if (!((XMLField) field).isRequired() && entry.getValue() instanceof JsonNull
+ && existingVertex.getProperties().containsKey(entry.getKey())) {
+ existingVertex.getProperties().remove(entry.getKey());
+ } else if (!(entry.getValue() instanceof JsonNull)) {
+ // add/update the value if found in existing vertex
+ Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(),
+ field.getType());
+ existingVertex.getProperties().put(entry.getKey(), value);
+ }
+
+ }
+
+ return existingVertex;
+ } catch (Exception e) {
+ throw new CrudException(e.getMessage(), Status.BAD_REQUEST);
+ }
+
+ }
+
+ private static DatabaseField getDatabaseField(String fieldName, DynamicType modelObjectType) {
+ for (DatabaseField field : modelObjectType.getDescriptor().getAllFields()) {
+ int ix = field.getName().indexOf("/");
+ if (ix <= 0) {
+ ix = field.getName().length();
+ }
+
+ String keyName = field.getName().substring(0, ix);
+ if (fieldName.equals(keyName)) {
+ return field;
+ }
+ }
+ return null;
+ }
+
+ public static Vertex validateOutgoingPayload(String version, Vertex vertex) {
+
+ Vertex.Builder modelVertexBuilder = new Vertex.Builder(vertex.getType())
+ .id(vertex.getId().get());
+
+ try {
+ DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version);
+ String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,
+ CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL,
+ vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()) != null
+ ? vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()).toString() : vertex.getType()));
+ final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass);
+
+ for (String key : vertex.getProperties().keySet()) {
+ DatabaseField field = getDatabaseField(key, modelObjectType);
+ if (field != null) {
+ if (!Metadata.isProperty(key)) {
+ modelVertexBuilder.property(key, vertex.getProperties().get(key));
+ }
+ }
+ }
+ return modelVertexBuilder.build();
+ } catch (Exception ex) {
+ return vertex;
+ }
+
+ }
+
+
+}
diff --git a/src/main/java/org/openecomp/schema/RelationshipSchema.java b/src/main/java/org/openecomp/schema/RelationshipSchema.java
new file mode 100644
index 0000000..5b28e28
--- /dev/null
+++ b/src/main/java/org/openecomp/schema/RelationshipSchema.java
@@ -0,0 +1,138 @@
+/**
+ * ============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.openecomp.schema;
+
+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 com.google.gson.JsonParser;
+
+import org.openecomp.crud.exception.CrudException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.ws.rs.core.Response.Status;
+
+public class RelationshipSchema {
+ private static final Gson gson = new GsonBuilder().create();
+
+ public static final String SCHEMA_SOURCE_NODE_TYPE = "source-node-type";
+ public static final String SCHEMA_TARGET_NODE_TYPE = "target-node-type";
+ public static final String SCHEMA_RELATIONSHIP_TYPE = "relationship-type";
+ public static final String SCHEMA_RELATIONSHIP_TYPES_ARRAY = "relationship-types";
+ public static final String SCHEMA_RELATIONSHIP_PROPERTIES = "properties";
+ public static final String SCHEMA_RELATIONS_ARRAY = "relations";
+
+ /**
+ * key = source-node-type:target-node-type:relationship-type value = map of properties with name
+ * and type . Like propertyName:PropertyType
+ */
+ private HashMap<String, HashMap<String, Class<?>>> relations
+ = new HashMap<String, HashMap<String, Class<?>>>();
+ /**
+ * Hashmap of valid relationship types alongwith properrties.
+ */
+ private HashMap<String, HashMap<String, Class<?>>> relationTypes
+ = new HashMap<String, HashMap<String, Class<?>>>();
+
+
+ public RelationshipSchema(String json) throws CrudException {
+
+ JsonParser parser = new JsonParser();
+ try {
+ JsonObject root = parser.parse(json).getAsJsonObject();
+ JsonArray relationshipTypesArray = root.getAsJsonArray(SCHEMA_RELATIONSHIP_TYPES_ARRAY);
+ JsonArray relationsArray = root.getAsJsonArray(SCHEMA_RELATIONS_ARRAY);
+
+ //First load all the relationship-types
+ for (JsonElement item : relationshipTypesArray) {
+ JsonObject obj = item.getAsJsonObject();
+ String type = obj.get(SCHEMA_RELATIONSHIP_TYPE).getAsString();
+
+
+ HashMap<String, Class<?>> props = new HashMap<String, Class<?>>();
+ Set<Map.Entry<String, JsonElement>> entries = obj.get(SCHEMA_RELATIONSHIP_PROPERTIES)
+ .getAsJsonObject().entrySet();
+
+ for (Map.Entry<String, JsonElement> entry : entries) {
+ props.put(entry.getKey(), resolveClass(entry.getValue().getAsString()));
+
+ }
+ relationTypes.put(type, props);
+
+ }
+
+ for (JsonElement item : relationsArray) {
+ JsonObject obj = item.getAsJsonObject();
+ // Parse the Source/Taget nodeTypes
+
+ String relationType = obj.get(SCHEMA_RELATIONSHIP_TYPE).getAsString();
+ String key = obj.get(SCHEMA_SOURCE_NODE_TYPE).getAsString() + ":"
+ + obj.get(SCHEMA_TARGET_NODE_TYPE).getAsString() + ":" + relationType;
+
+
+ if (!relationTypes.containsKey(relationType)) {
+ throw new CrudException(SCHEMA_RELATIONSHIP_TYPE + ": " + relationType + " not found",
+ Status.BAD_REQUEST);
+ }
+
+ relations.put(key, relationTypes.get(relationType));
+ }
+ } catch (Exception e) {
+ throw new CrudException(e.getMessage(), Status.BAD_REQUEST);
+ }
+
+ }
+
+
+ public HashMap<String, Class<?>> lookupRelation(String key) {
+ return this.relations.get(key);
+ }
+
+ public HashMap<String, Class<?>> lookupRelationType(String type) {
+ return this.relationTypes.get(type);
+ }
+
+ public boolean isValidType(String type) {
+ return relationTypes.containsKey(type);
+ }
+
+ private Class<?> resolveClass(String type) throws CrudException, ClassNotFoundException {
+ Class<?> clazz = Class.forName(type);
+ validateClassTypes(clazz);
+ return clazz;
+ }
+
+ private void validateClassTypes(Class<?> clazz) throws CrudException {
+ if (!clazz.isAssignableFrom(Integer.class) && !clazz.isAssignableFrom(Double.class)
+ && !clazz.isAssignableFrom(Boolean.class) && !clazz.isAssignableFrom(String.class)) {
+ throw new CrudException("", Status.BAD_REQUEST);
+ }
+ }
+
+
+}
diff --git a/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java b/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java
new file mode 100644
index 0000000..51b33d0
--- /dev/null
+++ b/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java
@@ -0,0 +1,158 @@
+/**
+ * ============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.openecomp.schema;
+
+import org.apache.commons.io.IOUtils;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.logging.CrudServiceMsgs;
+import org.openecomp.crud.util.CrudServiceConstants;
+import org.openecomp.crud.util.FileWatcher;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.bind.JAXBException;
+
+
+public class RelationshipSchemaLoader {
+
+ private static Map<String, RelationshipSchema> versionContextMap
+ = new ConcurrentHashMap<String, RelationshipSchema>();
+ private static SortedSet<Integer> versions = new TreeSet<Integer>();
+ private static Map<String, Timer> timers = new ConcurrentHashMap<String, Timer>();
+
+ final static Pattern filePattern = Pattern.compile("aai_relationship_(.*).json");
+
+
+ private static org.openecomp.cl.api.Logger logger = LoggerFactory.getInstance()
+ .getLogger(RelationshipSchemaLoader.class.getName());
+
+ public synchronized static void loadModels() {
+
+ File[] listOfFiles = new File(CrudServiceConstants.CRD_HOME_MODEL).listFiles();
+
+ if (listOfFiles != null) {
+ for (File file : listOfFiles) {
+ if (file.isFile()) {
+ Matcher matcher = filePattern.matcher(file.getName());
+ if (matcher.matches()) {
+ try {
+ RelationshipSchemaLoader.loadModel(matcher.group(1), file);
+ } catch (Exception e) {
+ logger.error(CrudServiceMsgs.INVALID_OXM_FILE, file.getName(), e.getMessage());
+ }
+ }
+
+ }
+ }
+ } else {
+ logger.error(CrudServiceMsgs.INVALID_OXM_DIR, CrudServiceConstants.CRD_HOME_MODEL);
+ }
+
+
+ }
+
+ private static void addtimer(String version, File file) {
+ TimerTask task = null;
+ task = new FileWatcher(
+ file) {
+ protected void onChange(File file) {
+ // here we implement the onChange
+ logger.info(CrudServiceMsgs.OXM_FILE_CHANGED, file.getName());
+
+ try {
+ RelationshipSchemaLoader.loadModel(version, file);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+ };
+
+ if (!timers.containsKey(version)) {
+ Timer timer = new Timer("aai_relationship_" + version);
+ timer.schedule(task, new Date(), 10000);
+ timers.put(version, timer);
+
+ }
+ }
+
+ private synchronized static void loadModel(String version, File file)
+ throws JAXBException, IOException, CrudException {
+
+ InputStream inputStream = new FileInputStream(file);
+ String content = IOUtils.toString(inputStream, "UTF-8");
+ versionContextMap.put(version, new RelationshipSchema(content));
+ addtimer(version, file);
+ versions.add(Integer.parseInt(version.substring(1)));
+ }
+
+ public static RelationshipSchema getSchemaForVersion(String version) throws CrudException {
+ if (versionContextMap == null || versionContextMap.isEmpty()) {
+ loadModels();
+ } else if (!versionContextMap.containsKey(version)) {
+ try {
+ loadModel(version, new File(CrudServiceConstants.CRD_HOME_MODEL + "aai_relationship_"
+ + version + ".json"));
+ } catch (Exception e) {
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+ }
+
+ return versionContextMap.get(version);
+ }
+
+ public static String getLatestSchemaVersion() throws CrudException {
+ return "v" + versions.last();
+ }
+
+ public static Map<String, RelationshipSchema> getVersionContextMap() {
+ return versionContextMap;
+ }
+
+ public static void setVersionContextMap(HashMap<String, RelationshipSchema> versionContextMap) {
+ RelationshipSchemaLoader.versionContextMap = versionContextMap;
+ }
+
+ public static void main(String[] args) throws FileNotFoundException, Exception {
+ File initialFile = new File("C:\\Software\\gizmo\\src\\main\\java\\org\\openecomp\\schema\\vio.json");
+
+ loadModel("v8", initialFile);
+ }
+
+}
diff --git a/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java b/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java
new file mode 100644
index 0000000..552b60a
--- /dev/null
+++ b/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java
@@ -0,0 +1,341 @@
+/**
+ * ============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.openecomp.schema;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+
+import org.openecomp.crud.entity.Edge;
+import org.openecomp.crud.entity.Vertex;
+import org.openecomp.crud.exception.CrudException;
+import org.openecomp.crud.service.EdgePayload;
+import org.openecomp.crud.util.CrudServiceUtil;
+import org.radeox.util.logging.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Response.Status;
+
+public class RelationshipSchemaValidator {
+
+ public static final String SOURCE_NODE = "source";
+ public static final String TARGET_NODE = "target";
+
+ final static Pattern urlPattern = Pattern.compile("services/inventory/(.*)/(.*)/(.*)");
+
+ public static Map<String, Object> resolveCollectionfilter(String version, String type,
+ Map<String, String> filter)
+ throws CrudException {
+
+ RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version);
+ if (schema == null) {
+ throw new CrudException("", Status.NOT_FOUND);
+ }
+
+ HashMap<String, Class<?>> props = schema.lookupRelationType(type);
+ Map<String, Object> result = new HashMap<String, Object>();
+
+ for (String key : filter.keySet()) {
+
+ if (props.containsKey(key)) {
+ try {
+ Object value = CrudServiceUtil.validateFieldType(filter.get(key), props.get(key));
+ result.put(key, value);
+ } catch (Exception ex) {
+ // Skip any exceptions thrown while validating the filter
+ // key value
+ continue;
+ }
+ }
+ }
+
+ return result;
+
+ }
+
+ public static void validateType(String version, String type) throws CrudException {
+
+ RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version);
+ if (!schema.isValidType(type)) {
+ throw new CrudException("Invalid " + RelationshipSchema.SCHEMA_RELATIONSHIP_TYPE
+ + ": " + type,
+ Status.BAD_REQUEST);
+ }
+
+ }
+
+ public static Edge validateIncomingAddPayload(String version, String type, Vertex sourceNode,
+ Vertex targetNode, JsonElement properties)
+ throws CrudException {
+ EdgePayload payload = new EdgePayload();
+ payload.setSource("services/inventory/" + version + "/" + sourceNode.getType()
+ + "/" + sourceNode.getId().get());
+ payload.setTarget("services/inventory/" + version + "/" + targetNode.getType()
+ + "/" + targetNode.getId().get());
+ payload.setType(type);
+ payload.setProperties(properties);
+ return validateIncomingAddPayload(version, type, payload);
+ }
+
+ public static Edge validateIncomingAddPayload(String version, String type, EdgePayload payload)
+ throws CrudException {
+ RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version);
+
+ try {
+
+ if (payload.getSource() == null || payload.getTarget() == null) {
+ throw new CrudException("Source/Target not specified", Status.BAD_REQUEST);
+ }
+
+ Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
+ Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
+
+ if (!sourceMatcher.matches() || !targetMatcher.matches()) {
+ throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST);
+ }
+
+ // create key based on source:target:relationshipType
+ String sourceNodeType = sourceMatcher.group(2);
+ String targetNodeType = targetMatcher.group(2);
+
+ String sourceNodeId = sourceMatcher.group(3);
+ String targetNodeId = targetMatcher.group(3);
+
+ String key = sourceNodeType + ":" + targetNodeType + ":" + type;
+
+ // find the validate the key from the schema
+ HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key);
+
+ if (schemaObject == null) {
+ throw new CrudException("Invalid source/target/relationship type: " + key,
+ Status.BAD_REQUEST);
+ }
+
+ Edge.Builder modelEdgeBuilder = new Edge.Builder(type);
+
+ modelEdgeBuilder.source(new Vertex.Builder(sourceNodeType).id(sourceNodeId).build());
+ modelEdgeBuilder.target(new Vertex.Builder(targetNodeType).id(targetNodeId).build());
+
+ // validate it properties
+ validateEdgeProps(modelEdgeBuilder, payload.getProperties(), schemaObject);
+
+ return modelEdgeBuilder.build();
+ } catch (Exception ex) {
+
+ throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
+ }
+
+ }
+
+ public static Edge validateIncomingPatchPayload(Edge edge, String version, EdgePayload payload)
+ throws CrudException {
+ RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version);
+
+ try {
+ if (payload.getSource() != null) {
+ Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
+
+ if (!sourceMatcher.matches()) {
+ throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
+ }
+ String sourceNodeId = sourceMatcher.group(3);
+ if (!sourceNodeId.equals(edge.getSource().getId().get())) {
+ throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
+ }
+ }
+
+ if (payload.getTarget() != null) {
+ Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
+
+ if (!targetMatcher.matches()) {
+ throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
+ }
+ String sourceNodeId = targetMatcher.group(3);
+ if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
+ throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
+ }
+ }
+ // create key based on source:target:relationshipType
+
+ String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
+ + ":" + edge.getType();
+
+ // find the validate the key from the schema
+ HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key);
+
+ if (schemaObject == null) {
+ Logger.warn("key :" + key
+ + " not found in relationship schema . Skipping the schema validation");
+ return edge;
+ }
+
+ Set<Map.Entry<String, JsonElement>> entries = payload.getProperties()
+ .getAsJsonObject().entrySet();
+
+ for (Map.Entry<String, JsonElement> entry : entries) {
+
+ if (!schemaObject.containsKey(entry.getKey())) {
+ throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
+ } else if (entry.getValue() instanceof JsonNull && edge.getProperties()
+ .containsKey(entry.getKey())) {
+ edge.getProperties().remove(entry.getKey());
+ } else if (!(entry.getValue() instanceof JsonNull)) {
+ Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(),
+ schemaObject.get(entry.getKey()));
+ edge.getProperties().put(entry.getKey(), value);
+ }
+
+ }
+
+ return edge;
+
+ } catch (Exception ex) {
+
+ throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
+ }
+ }
+
+ public static Edge validateIncomingUpdatePayload(Edge edge, String version, Vertex sourceNode,
+ Vertex targetNode, JsonElement properties)
+ throws CrudException {
+ EdgePayload payload = new EdgePayload();
+ payload.setSource("services/inventory/" + version + "/" + sourceNode.getType()
+ + "/" + sourceNode.getId().get());
+ payload.setTarget("services/inventory/" + version + "/" + targetNode.getType()
+ + "/" + targetNode.getId().get());
+ payload.setType(edge.getType());
+ payload.setProperties(properties);
+ return validateIncomingUpdatePayload(edge, version, payload);
+ }
+
+ public static Edge validateIncomingUpdatePayload(Edge edge, String version, EdgePayload payload)
+ throws CrudException {
+ RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version);
+
+ try {
+
+ if (payload.getSource() != null) {
+ Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
+
+ if (!sourceMatcher.matches()) {
+ throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
+ }
+ String sourceNodeId = sourceMatcher.group(3);
+ if (!sourceNodeId.equals(edge.getSource().getId().get())) {
+ throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
+ }
+ }
+
+ if (payload.getTarget() != null) {
+ Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
+
+ if (!targetMatcher.matches()) {
+ throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
+ }
+ String sourceNodeId = targetMatcher.group(3);
+ if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
+ throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
+ }
+ }
+ // create key based on source:target:relationshipType
+
+ String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
+ + ":" + edge.getType();
+
+ // find the validate the key from the schema
+ HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key);
+
+ if (schemaObject == null) {
+ Logger.warn("key :" + key
+ + " not found in relationship schema . Skipping the schema validation");
+ return edge;
+ }
+
+ Edge.Builder updatedEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId().get());
+
+ updatedEdgeBuilder
+ .source(new Vertex.Builder(edge.getSource().getType()).id(edge.getSource().getId()
+ .get()).build());
+ updatedEdgeBuilder
+ .target(new Vertex.Builder(edge.getTarget().getType()).id(edge.getTarget().getId()
+ .get()).build());
+
+ validateEdgeProps(updatedEdgeBuilder, payload.getProperties(), schemaObject);
+
+ return updatedEdgeBuilder.build();
+ } catch (Exception ex) {
+
+ throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
+ }
+ }
+
+
+ private static void validateEdgeProps(Edge.Builder builder, JsonElement props,
+ HashMap<String, Class<?>> schemaObject)
+ throws CrudException {
+ Set<Map.Entry<String, JsonElement>> entries = props.getAsJsonObject().entrySet();
+
+ for (Map.Entry<String, JsonElement> entry : entries) {
+
+ if (!schemaObject.containsKey(entry.getKey())) {
+ throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
+ } else {
+ Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(),
+ schemaObject.get(entry.getKey()));
+ builder.property(entry.getKey(), value);
+ }
+
+ }
+
+ }
+
+ public static Edge validateOutgoingPayload(String version, Edge edge) throws CrudException {
+
+ Edge.Builder modelEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId()
+ .get()).source(edge.getSource())
+ .target(edge.getTarget());
+
+ RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version);
+
+ String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
+ + ":" + edge.getType();
+ HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key);
+
+ if (schemaObject == null || schemaObject.isEmpty()) {
+ return edge;
+ }
+
+ for (String prop : edge.getProperties().keySet()) {
+ if (schemaObject.containsKey(prop)) {
+ modelEdgeBuilder.property(prop, edge.getProperties().get(prop));
+ }
+
+ }
+ return modelEdgeBuilder.build();
+ }
+
+}