diff options
author | Shwetank Dave <shwetank.dave@amdocs.com> | 2017-08-02 17:10:38 -0400 |
---|---|---|
committer | Shwetank Dave <shwetank.dave@amdocs.com> | 2017-08-03 11:28:39 -0400 |
commit | e9c94429a8ada3e55854515060df817945b73d87 (patch) | |
tree | 3c5a9ac766d99570d542c1996f1321c99e5498e5 /src/main/java/org/openecomp/crud | |
parent | 27ff75c77611a8bdae37c7c0092787938c63a786 (diff) |
[AAI-26] Adding gizmo data to the repository.
Change-Id: I183f837d45acbfe3c673fde1acf8768d5e3fd37b
Signed-off-by: Shwetank Dave <shwetank.dave@amdocs.com>
Diffstat (limited to 'src/main/java/org/openecomp/crud')
21 files changed, 3727 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 |