Commit 32a5b761 by Shwetha GS

ATLAS-698 Remove Rexster Graph API (svimal2106 via shwethags)

parent 814f066d
......@@ -12,6 +12,7 @@ ATLAS-925 Change master version to 0.8-incubating (shwethags)
--Release 0.7-incubating
INCOMPATIBLE CHANGES:
ATLAS-698 Remove Rexster Graph API (svimal2106 via shwethags)
ATLAS-844 Remove titan berkeley and elastic search jars if hbase/solr based profiles are chosen (yhemanth via shwethags)
ATLAS-819 All user defined types should have a set of common attributes (shwethags)
ATLAS-915 Fix docs for import-hive changes (svimal2106 via sumasai)
......
......@@ -41,6 +41,7 @@ import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.classification.InterfaceAudience;
/**
* Jersey Resource for metadata operations.
......@@ -82,10 +83,6 @@ public class MetadataDiscoveryResource {
try { // fall back to dsl
ParamChecker.notEmpty(query, "query cannot be null");
if (query.startsWith("g.")) { // raw gremlin query
return searchUsingGremlinQuery(query);
}
final String jsonResultStr = discoveryService.searchByDSL(query);
response = new DSLJSONResponseBuilder().results(jsonResultStr).query(query).build();
return Response.ok(response).build();
......@@ -137,6 +134,7 @@ public class MetadataDiscoveryResource {
@Path("search/gremlin")
@Consumes(Servlets.JSON_MEDIA_TYPE)
@Produces(Servlets.JSON_MEDIA_TYPE)
@InterfaceAudience.Private
public Response searchUsingGremlinQuery(@QueryParam("query") String gremlinQuery) {
try {
ParamChecker.notEmpty(gremlinQuery, "gremlinQuery cannot be null or empty");
......
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.atlas.web.resources;
import com.thinkaurelius.titan.core.TitanGraph;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.VertexQuery;
import com.tinkerpop.blueprints.util.io.graphson.GraphSONMode;
import com.tinkerpop.blueprints.util.io.graphson.GraphSONUtility;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.repository.graph.GraphProvider;
import org.apache.atlas.web.util.Servlets;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Jersey Resource for lineage metadata operations.
* Implements most of the GET operations of Rexster API with out the indexes.
* https://github.com/tinkerpop/rexster/wiki/Basic-REST-API
*
* This is a subset of Rexster's REST API, designed to provide only read-only methods
* for accessing the backend graph.
*/
@Path("graph")
@Singleton
public class RexsterGraphResource {
public static final String OUT_E = "outE";
public static final String IN_E = "inE";
public static final String BOTH_E = "bothE";
public static final String OUT = "out";
public static final String IN = "in";
public static final String BOTH = "both";
public static final String OUT_COUNT = "outCount";
public static final String IN_COUNT = "inCount";
public static final String BOTH_COUNT = "bothCount";
public static final String OUT_IDS = "outIds";
public static final String IN_IDS = "inIds";
public static final String BOTH_IDS = "bothIds";
private static final Logger LOG = LoggerFactory.getLogger(RexsterGraphResource.class);
private TitanGraph graph;
@Inject
public RexsterGraphResource(GraphProvider<TitanGraph> graphProvider) {
this.graph = graphProvider.get();
}
private static void validateInputs(String errorMsg, String... inputs) {
for (String input : inputs) {
if (StringUtils.isEmpty(input)) {
throw new WebApplicationException(
Response.status(Response.Status.BAD_REQUEST).entity(errorMsg).type("text/plain").build());
}
}
}
protected Graph getGraph() {
return graph;
}
protected Set<String> getVertexIndexedKeys() {
return graph.getIndexedKeys(Vertex.class);
}
protected Set<String> getEdgeIndexedKeys() {
return graph.getIndexedKeys(Edge.class);
}
/**
* Get a single vertex with a unique id.
*
* GET http://host/metadata/lineage/vertices/id
* graph.getVertex(id);
*/
@GET
@Path("/vertices/{id}")
@Produces({Servlets.JSON_MEDIA_TYPE})
public Response getVertex(@PathParam("id") final String vertexId) {
LOG.info("Get vertex for vertexId= {}", vertexId);
validateInputs("Invalid argument: vertex id passed is null or empty.", vertexId);
try {
Vertex vertex = findVertex(vertexId);
JSONObject response = new JSONObject();
response.put(AtlasClient.RESULTS,
GraphSONUtility.jsonFromElement(vertex, getVertexIndexedKeys(), GraphSONMode.NORMAL));
return Response.ok(response).build();
} catch (JSONException e) {
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
private Vertex findVertex(String vertexId) {
Vertex vertex = getGraph().getVertex(vertexId);
if (vertex == null) {
String message = "Vertex with [" + vertexId + "] cannot be found.";
LOG.info(message);
throw new WebApplicationException(Servlets.getErrorResponse(message, Response.Status.NOT_FOUND));
}
return vertex;
}
/**
* Get properties for a single vertex with a unique id.
* This is NOT a rexster API.
* <p/>
* GET http://host/metadata/lineage/vertices/properties/id
*/
@GET
@Path("/vertices/properties/{id}")
@Produces({Servlets.JSON_MEDIA_TYPE})
public Response getVertexProperties(@PathParam("id") final String vertexId,
@DefaultValue("false") @QueryParam("relationships") final String relationships) {
LOG.info("Get vertex for vertexId= {}", vertexId);
validateInputs("Invalid argument: vertex id passed is null or empty.", vertexId);
try {
Vertex vertex = findVertex(vertexId);
Map<String, String> vertexProperties = getVertexProperties(vertex);
JSONObject response = new JSONObject();
response.put(AtlasClient.RESULTS, new JSONObject(vertexProperties));
response.put(AtlasClient.COUNT, vertexProperties.size());
return Response.ok(response).build();
} catch (JSONException e) {
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
private Map<String, String> getVertexProperties(Vertex vertex) {
Map<String, String> vertexProperties = new HashMap<>();
for (String key : vertex.getPropertyKeys()) {
vertexProperties.put(key, vertex.<String>getProperty(key));
}
// todo: get the properties from relationships
return vertexProperties;
}
/**
* Get a list of vertices matching a property key and a value.
* <p/>
* GET http://host/metadata/lineage/vertices?key=<key>&value=<value>
* graph.getVertices(key, value);
*/
@GET
@Path("/vertices")
@Produces({Servlets.JSON_MEDIA_TYPE})
public Response getVertices(@QueryParam("key") final String key, @QueryParam("value") final String value) {
LOG.info("Get vertices for property key= {}, value= {}", key, value);
validateInputs("Invalid argument: key or value passed is null or empty.", key, value);
try {
JSONObject response = buildJSONResponse(getGraph().getVertices(key, value));
return Response.ok(response).build();
} catch (JSONException e) {
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
/**
* Get a list of adjacent edges with a direction.
*
* GET http://host/metadata/lineage/vertices/id/direction
* graph.getVertex(id).get{Direction}Edges();
* direction: {(?!outE)(?!bothE)(?!inE)(?!out)(?!both)(?!in)(?!query).+}
*/
@GET
@Path("vertices/{id}/{direction}")
@Produces({Servlets.JSON_MEDIA_TYPE})
public Response getVertexEdges(@PathParam("id") String vertexId, @PathParam("direction") String direction) {
LOG.info("Get vertex edges for vertexId= {}, direction= {}", vertexId, direction);
// Validate vertex id. Direction is validated in VertexQueryArguments.
validateInputs("Invalid argument: vertex id or direction passed is null or empty.", vertexId, direction);
try {
Vertex vertex = findVertex(vertexId);
return getVertexEdges(vertex, direction);
} catch (JSONException e) {
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
private Response getVertexEdges(Vertex vertex, String direction) throws JSONException {
// break out the segment into the return and the direction
VertexQueryArguments queryArguments = new VertexQueryArguments(direction);
// if this is a query and the _return is "count" then we don't bother to send back the
// result array
boolean countOnly = queryArguments.isCountOnly();
// what kind of data the calling client wants back (vertices, edges, count, vertex
// identifiers)
ReturnType returnType = queryArguments.getReturnType();
// the query direction (both, out, in)
Direction queryDirection = queryArguments.getQueryDirection();
VertexQuery query = vertex.query().direction(queryDirection);
JSONArray elementArray = new JSONArray();
long counter = 0;
if (returnType == ReturnType.VERTICES || returnType == ReturnType.VERTEX_IDS) {
Iterable<Vertex> vertexQueryResults = query.vertices();
for (Vertex v : vertexQueryResults) {
if (returnType.equals(ReturnType.VERTICES)) {
elementArray.put(GraphSONUtility.jsonFromElement(v, getVertexIndexedKeys(), GraphSONMode.NORMAL));
} else {
elementArray.put(v.getId());
}
counter++;
}
} else if (returnType == ReturnType.EDGES) {
Iterable<Edge> edgeQueryResults = query.edges();
for (Edge e : edgeQueryResults) {
elementArray.put(GraphSONUtility.jsonFromElement(e, getEdgeIndexedKeys(), GraphSONMode.NORMAL));
counter++;
}
} else if (returnType == ReturnType.COUNT) {
counter = query.count();
}
JSONObject response = new JSONObject();
if (!countOnly) {
response.put(AtlasClient.RESULTS, elementArray);
}
response.put(AtlasClient.COUNT, counter);
return Response.ok(response).build();
}
/**
* Get a single edge with a unique id.
*
* GET http://host/metadata/lineage/edges/id
* graph.getEdge(id);
*/
@GET
@Path("/edges/{id}")
@Produces({Servlets.JSON_MEDIA_TYPE})
public Response getEdge(@PathParam("id") final String edgeId) {
LOG.info("Get vertex for edgeId= {}", edgeId);
validateInputs("Invalid argument: edge id passed is null or empty.", edgeId);
try {
Edge edge = getGraph().getEdge(edgeId);
if (edge == null) {
String message = "Edge with [" + edgeId + "] cannot be found.";
LOG.info(message);
throw new WebApplicationException(
Response.status(Response.Status.NOT_FOUND).entity(Servlets.escapeJsonString(message)).build());
}
JSONObject response = new JSONObject();
response.put(AtlasClient.RESULTS,
GraphSONUtility.jsonFromElement(edge, getEdgeIndexedKeys(), GraphSONMode.NORMAL));
return Response.ok(response).build();
} catch (JSONException e) {
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
private <T extends Element> JSONObject buildJSONResponse(Iterable<T> elements) throws JSONException {
JSONArray vertexArray = new JSONArray();
long counter = 0;
for (Element element : elements) {
counter++;
vertexArray.put(GraphSONUtility.jsonFromElement(element, getVertexIndexedKeys(), GraphSONMode.NORMAL));
}
JSONObject response = new JSONObject();
response.put(AtlasClient.RESULTS, vertexArray);
response.put(AtlasClient.COUNT, counter);
return response;
}
private enum ReturnType {VERTICES, EDGES, COUNT, VERTEX_IDS}
/**
* Helper class for query arguments.
*/
public static final class VertexQueryArguments {
private final Direction queryDirection;
private final ReturnType returnType;
private final boolean countOnly;
public VertexQueryArguments(String directionSegment) {
if (OUT_E.equals(directionSegment)) {
returnType = ReturnType.EDGES;
queryDirection = Direction.OUT;
countOnly = false;
} else if (IN_E.equals(directionSegment)) {
returnType = ReturnType.EDGES;
queryDirection = Direction.IN;
countOnly = false;
} else if (BOTH_E.equals(directionSegment)) {
returnType = ReturnType.EDGES;
queryDirection = Direction.BOTH;
countOnly = false;
} else if (OUT.equals(directionSegment)) {
returnType = ReturnType.VERTICES;
queryDirection = Direction.OUT;
countOnly = false;
} else if (IN.equals(directionSegment)) {
returnType = ReturnType.VERTICES;
queryDirection = Direction.IN;
countOnly = false;
} else if (BOTH.equals(directionSegment)) {
returnType = ReturnType.VERTICES;
queryDirection = Direction.BOTH;
countOnly = false;
} else if (BOTH_COUNT.equals(directionSegment)) {
returnType = ReturnType.COUNT;
queryDirection = Direction.BOTH;
countOnly = true;
} else if (IN_COUNT.equals(directionSegment)) {
returnType = ReturnType.COUNT;
queryDirection = Direction.IN;
countOnly = true;
} else if (OUT_COUNT.equals(directionSegment)) {
returnType = ReturnType.COUNT;
queryDirection = Direction.OUT;
countOnly = true;
} else if (BOTH_IDS.equals(directionSegment)) {
returnType = ReturnType.VERTEX_IDS;
queryDirection = Direction.BOTH;
countOnly = false;
} else if (IN_IDS.equals(directionSegment)) {
returnType = ReturnType.VERTEX_IDS;
queryDirection = Direction.IN;
countOnly = false;
} else if (OUT_IDS.equals(directionSegment)) {
returnType = ReturnType.VERTEX_IDS;
queryDirection = Direction.OUT;
countOnly = false;
} else {
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
.entity(Servlets.escapeJsonString(directionSegment + " segment was invalid.")).build());
}
}
public Direction getQueryDirection() {
return queryDirection;
}
public ReturnType getReturnType() {
return returnType;
}
public boolean isCountOnly() {
return countOnly;
}
}
}
......@@ -100,7 +100,7 @@ public class MetadataDiscoveryJerseyResourceIT extends BaseResourceIT {
@Test
public void testSearchUsingGremlin() throws Exception {
String query = "g.V.has('type', 'dsl_test_type').toList()";
WebResource resource = service.path("api/atlas/discovery/search").queryParam("query", query);
WebResource resource = service.path("api/atlas/discovery/search/gremlin").queryParam("query", query);
ClientResponse clientResponse = resource.accept(Servlets.JSON_MEDIA_TYPE).type(Servlets.JSON_MEDIA_TYPE)
.method(HttpMethod.GET, ClientResponse.class);
......
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.atlas.web.resources;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import org.apache.atlas.web.util.Servlets;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.Response;
/**
* Integration tests for Rexster Graph Jersey Resource.
*/
@Test
public class RexsterGraphJerseyResourceIT extends BaseResourceIT {
@BeforeClass
@Override
public void setUp() throws Exception {
super.setUp();
}
@Test(enabled = false)
public void testGetVertex() throws Exception {
// todo: add a vertex before fetching it
WebResource resource = service.path("api/atlas/graph/vertices").path("0");
ClientResponse clientResponse = resource.accept(Servlets.JSON_MEDIA_TYPE).type(Servlets.JSON_MEDIA_TYPE)
.method(HttpMethod.GET, ClientResponse.class);
Assert.assertEquals(clientResponse.getStatus(), Response.Status.OK.getStatusCode());
String response = clientResponse.getEntity(String.class);
Assert.assertNotNull(response);
}
public void testGetVertexWithInvalidId() throws Exception {
WebResource resource = service.path("api/atlas/graph/vertices/blah");
ClientResponse clientResponse = resource.accept(Servlets.JSON_MEDIA_TYPE).type(Servlets.JSON_MEDIA_TYPE)
.method(HttpMethod.GET, ClientResponse.class);
Assert.assertEquals(clientResponse.getStatus(), Response.Status.NOT_FOUND.getStatusCode());
}
public void testGetVertexProperties() throws Exception {
}
public void testGetVertices() throws Exception {
}
public void testGetVertexEdges() throws Exception {
}
public void testGetEdge() throws Exception {
}
}
......@@ -26,7 +26,6 @@ import org.apache.atlas.web.TestUtils;
import org.apache.atlas.web.resources.AdminJerseyResourceIT;
import org.apache.atlas.web.resources.EntityJerseyResourceIT;
import org.apache.atlas.web.resources.MetadataDiscoveryJerseyResourceIT;
import org.apache.atlas.web.resources.RexsterGraphJerseyResourceIT;
import org.apache.atlas.web.resources.TypesJerseyResourceIT;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.hadoop.conf.Configuration;
......@@ -173,7 +172,7 @@ public class SecureEmbeddedServerTestBase {
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses(new Class[]{AdminJerseyResourceIT.class, EntityJerseyResourceIT.class,
MetadataDiscoveryJerseyResourceIT.class, RexsterGraphJerseyResourceIT.class,
MetadataDiscoveryJerseyResourceIT.class,
TypesJerseyResourceIT.class});
testng.addListener(tla);
testng.run();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment