package com.tinkerpop.rexster;
import com.codahale.metrics.annotation.Timed;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.KeyIndexableGraph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.rexster.extension.HttpMethod;
import com.tinkerpop.rexster.server.RexsterApplication;
import org.apache.log4j.Logger;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.HashMap;
/**
* Key index resource.
*
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
@Path("/graphs/{graphname}/keyindices")
public class KeyIndexResource extends AbstractSubResource {
private static final Logger logger = Logger.getLogger(EdgeResource.class);
public KeyIndexResource() {
super(null);
}
public KeyIndexResource(final UriInfo ui, final HttpServletRequest req, final RexsterApplication ra) {
super(ra);
this.httpServletRequest = req;
this.uriInfo = ui;
}
@OPTIONS
public Response optionsKeyIndices() {
return buildOptionsResponse(HttpMethod.GET.toString());
}
@GET
@Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
@Timed(name = "http.rest.key-indices.collection.get", absolute = true)
public Response getKeyIndices(@PathParam("graphname") final String graphName) {
final KeyIndexableGraph graph = this.getKeyIndexableGraph(graphName);
final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName);
try {
final JSONArray keyVertexArray = new JSONArray();
for (String key : graph.getIndexedKeys(Vertex.class)) {
keyVertexArray.put(key);
}
final JSONArray keyEdgeArray = new JSONArray();
for (String key : graph.getIndexedKeys(Edge.class)) {
keyEdgeArray.put(key);
}
this.resultObject.put(Tokens.RESULTS, new JSONObject(new HashMap() {{
put(Tokens.VERTEX, keyVertexArray);
put(Tokens.EDGE, keyEdgeArray);
}}));
this.resultObject.put(Tokens.QUERY_TIME, this.sh.stopWatch());
} catch (JSONException ex) {
logger.error(ex);
final JSONObject error = generateErrorObjectJsonFail(ex);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build());
} finally {
rag.tryCommit();
}
return Response.ok(this.resultObject).build();
}
@OPTIONS
@Path("/{clazz}")
public Response optionsIndexKeys() {
return buildOptionsResponse(HttpMethod.GET.toString());
}
@GET
@Path("/{clazz}")
@Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
@Timed(name = "http.rest.key-indices.class.collection.get", absolute = true)
public Response getIndexKeys(@PathParam("graphname") final String graphName, @PathParam("clazz") final String clazz) {
final Class<? extends Element> keyClass;
if (clazz.equals(Tokens.VERTEX)) {
keyClass = Vertex.class;
} else if (clazz.equals(Tokens.EDGE)) {
keyClass = Edge.class;
} else {
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
final KeyIndexableGraph graph = this.getKeyIndexableGraph(graphName);
final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName);
try {
final JSONArray keyArray = new JSONArray();
for (String key : graph.getIndexedKeys(keyClass)) {
keyArray.put(key);
}
this.resultObject.put(Tokens.RESULTS, keyArray);
this.resultObject.put(Tokens.QUERY_TIME, this.sh.stopWatch());
} catch (JSONException ex) {
logger.error(ex);
final JSONObject error = generateErrorObjectJsonFail(ex);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build());
} finally {
rag.tryCommit();
}
return Response.ok(this.resultObject).build();
}
@OPTIONS
@Path("/{clazz}/{keyName}")
public Response optionsIndexKey() {
return buildOptionsResponse(HttpMethod.DELETE.toString(),
HttpMethod.POST.toString());
}
@DELETE
@Path("{clazz}/{keyName}")
@Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
@Timed(name = "http.rest.key-indices.object.delete", absolute = true)
public Response deleteIndexKey(@PathParam("graphname") final String graphName, @PathParam("clazz") final String clazz,
@PathParam("keyName") final String keyName) {
final Class keyClass;
if (clazz.equals(Tokens.VERTEX)) {
keyClass = Vertex.class;
} else if (clazz.equals(Tokens.EDGE)) {
keyClass = Edge.class;
} else {
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
if (keyName == null || keyName.isEmpty()) {
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName);
final KeyIndexableGraph graph = this.getKeyIndexableGraph(graphName);
try {
graph.dropKeyIndex(keyName, keyClass);
rag.tryCommit();
this.resultObject.put(Tokens.QUERY_TIME, this.sh.stopWatch());
} catch (JSONException ex) {
logger.error(ex);
rag.tryRollback();
final JSONObject error = generateErrorObjectJsonFail(ex);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build());
}
return Response.ok(this.resultObject).build();
}
@POST
@Path("/{clazz}/{keyName}")
@Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
@Timed(name = "http.rest.key-indices.class.object.post", absolute = true)
public Response postIndexKey(@PathParam("graphname") final String graphName, @PathParam("clazz") final String clazz,
@PathParam("keyName") final String keyName) {
final Class keyClass;
if (clazz.equals(Tokens.VERTEX)) {
keyClass = Vertex.class;
} else if (clazz.equals(Tokens.EDGE)) {
keyClass = Edge.class;
} else {
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
if (keyName == null || keyName.isEmpty()) {
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName);
final KeyIndexableGraph graph = this.getKeyIndexableGraph(graphName);
try {
graph.createKeyIndex(keyName, keyClass);
rag.tryCommit();
this.resultObject.put(Tokens.QUERY_TIME, this.sh.stopWatch());
} catch (JSONException ex) {
logger.error(ex);
rag.tryRollback();
final JSONObject error = generateErrorObjectJsonFail(ex);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build());
}
return Response.ok(this.resultObject).build();
}
private KeyIndexableGraph getKeyIndexableGraph(final String graphName) {
final Graph graph = this.getRexsterApplicationGraph(graphName).getUnwrappedGraph();
final KeyIndexableGraph idxGraph = graph instanceof KeyIndexableGraph ? (KeyIndexableGraph) graph : null;
if (idxGraph == null) {
final JSONObject error = this.generateErrorObject("The requested graph is not of type IndexableGraph.");
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build());
}
return idxGraph;
}
}