All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tinkerpop.rexster.IndexResource Maven / Gradle / Ivy

package com.tinkerpop.rexster;

import com.codahale.metrics.annotation.Timed;
import com.tinkerpop.blueprints.CloseableIterable;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Index;
import com.tinkerpop.blueprints.IndexableGraph;
import com.tinkerpop.blueprints.Parameter;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.util.io.graphson.GraphSONMode;
import com.tinkerpop.blueprints.util.io.graphson.GraphSONUtility;
import com.tinkerpop.rexster.extension.HttpMethod;
import com.tinkerpop.rexster.server.RexsterApplication;
import com.tinkerpop.rexster.util.ElementHelper;
import com.tinkerpop.rexster.util.RequestObjectHelper;
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.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
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.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Resource for graph indices.
 *
 * @author Marko A. Rodriguez (http://markorodriguez.com)
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
@Path("/graphs/{graphname}/indices")
public class IndexResource extends AbstractSubResource {

    private static final Logger logger = Logger.getLogger(EdgeResource.class);

    public IndexResource() {
        super(null);
    }

    public IndexResource(final UriInfo ui, final HttpServletRequest req, final RexsterApplication ra) {
        super(ra);
        this.httpServletRequest = req;
        this.uriInfo = ui;
    }

    @OPTIONS
    public Response optionsAllIndices() {
        return buildOptionsResponse(HttpMethod.GET.toString());
    }

    /**
     * GET http://host/graph/indices
     * get.getIndices();
     */
    @GET
    @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
    @Timed(name = "http.rest.indices.collection.get", absolute = true)
    public Response getAllIndices(@PathParam("graphname") final String graphName) {
        final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName);
        final Graph graph = rag.getGraph();

        final JSONObject theRequestObject = this.getRequestObject();

        final IndexableGraph idxGraph = graph instanceof IndexableGraph ? (IndexableGraph) graph : null;

        if (idxGraph == null) {
            final JSONObject error = this.generateErrorObject("The requested graph is not of type " + IndexableGraph.class.getName() + ".");
            throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build());
        }

        final Long start = RequestObjectHelper.getStartOffset(theRequestObject);
        final Long end = RequestObjectHelper.getEndOffset(theRequestObject);

        long counter = 0l;

        try {
            final JSONArray indexArray = new JSONArray();
            for (Index index : idxGraph.getIndices()) {
                if (counter >= start && counter < end) {
                    indexArray.put(createJSONObject(index));
                }
                counter++;
            }

            this.resultObject.put(Tokens.RESULTS, indexArray);
            this.resultObject.put(Tokens.TOTAL_SIZE, counter);
            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("/{indexName}")
    public Response optionsElementsFromIndex() {
        return buildOptionsResponse(HttpMethod.GET.toString(),
                HttpMethod.DELETE.toString(),
                HttpMethod.POST.toString(),
                HttpMethod.PUT.toString());
    }

    /**
     * GET http://host/graph/indices/indexName?key=key1&value=value1
     * Index index = graph.getIndex(indexName,...);
     * index.get(key,value);
     */
    @GET
    @Path("/{indexName}")
    @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON})
    @Timed(name = "http.rest.indices.object.get", absolute = true)
    public Response getElementsFromIndex(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName) {
        return this.getElementsFromIndex(graphName, indexName, false);
    }

    @GET
    @Path("/{indexName}")
    @Produces({RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
    @Timed(name = "http.rest.indices.object.get", absolute = true)
    public Response getElementsFromIndexRexsterTypedJson(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName) {
        return this.getElementsFromIndex(graphName, indexName, true);
    }

    private Response getElementsFromIndex(final String graphName, final String indexName, final boolean showTypes) {
        final Index index = this.getIndexFromGraph(graphName, indexName);
        final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName);

        String key = null;
        Object value = null;

        final JSONObject theRequestObject = this.getRequestObject();

        Object temp = theRequestObject.opt(Tokens.KEY);
        if (null != temp)
            key = temp.toString();

        temp = theRequestObject.opt(Tokens.VALUE);
        if (null != temp)
            value = ElementHelper.getTypedPropertyValue(temp.toString());

        final Long start = RequestObjectHelper.getStartOffset(theRequestObject);
        final Long end = RequestObjectHelper.getEndOffset(theRequestObject);
        final Set returnKeys = RequestObjectHelper.getReturnKeys(theRequestObject);
        final GraphSONMode mode = showTypes ? GraphSONMode.EXTENDED : GraphSONMode.NORMAL;

        long counter = 0l;

        if (null != index && key != null && value != null) {
            final CloseableIterable indexElements = (CloseableIterable) index.get(key, value);
            try {

                final JSONArray elementArray = new JSONArray();
                for (Element element : indexElements) {
                    if (counter >= start && counter < end) {
                        elementArray.put(GraphSONUtility.jsonFromElement(element, returnKeys, mode));
                    }
                    counter++;
                }

                this.resultObject.put(Tokens.RESULTS, elementArray);
                this.resultObject.put(Tokens.TOTAL_SIZE, counter);
                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 {
                indexElements.close();
                rag.tryCommit();
            }
        } else if (null == index) {
            final String msg = "Could not find index [" + indexName + "] on graph [" + graphName + "]";
            logger.info(msg);

            final JSONObject error = generateErrorObject(msg);
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).entity(error).build());
        } else {
            // return info about the index itself
            final HashMap map = new HashMap();
            map.put(Tokens.QUERY_TIME, this.sh.stopWatch());
            map.put(Tokens.RESULTS, createJSONObject(index));

            this.resultObject = new JSONObject(map);
        }

        return Response.ok(this.resultObject).build();
    }

    @OPTIONS
    @Path("/{indexName}/count")
    @Timed(name = "http.rest.indices.count.get", absolute = true)
    public Response optionsIndexCount() {
        return buildOptionsResponse(HttpMethod.GET.toString());
    }

    /**
     * GET http://host/graph/indices/indexName/count?key=?&value=?
     */
    @GET
    @Path("/{indexName}/count")
    @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
    @Timed(name = "http.rest.indices.count.get", absolute = true)
    public Response getIndexCount(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName) {
        final Index index = this.getIndexFromGraph(graphName, indexName);
        final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName);

        String key = null;
        Object value = null;

        final JSONObject theRequestObject = this.getRequestObject();

        Object temp = theRequestObject.opt(Tokens.KEY);
        if (temp != null) {
            key = temp.toString();
        }

        temp = theRequestObject.opt(Tokens.VALUE);
        if (temp != null) {
            value = ElementHelper.getTypedPropertyValue(temp.toString());
        }

        if (index != null && key != null && value != null) {
            try {
                final long count = index.count(key, value);

                this.resultObject.put(Tokens.TOTAL_SIZE, count);
                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();
            }
        } else if (null == index) {
            final String msg = "Could not find index [" + indexName + "] on graph [" + graphName + "]";
            logger.info(msg);

            final JSONObject error = generateErrorObject(msg);
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).entity(error).build());
        } else {
            final String msg = "A key and value must be provided to lookup elements in an index";
            logger.info(msg);

            final JSONObject error = generateErrorObject(msg);
            throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build());
        }

        return Response.ok(this.resultObject).build();
    }

    @DELETE
    @Path("/{indexName}")
    @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
    @Consumes({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON})
    @Timed(name = "http.rest.indices.object.delete", absolute = true)
    public Response deleteIndex(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName, final JSONObject json) {
        // initializes the request object with the data DELETEed to the resource.  URI parameters
        // will then be ignored when the getRequestObject is called as the request object will
        // have already been established.
        this.setRequestObject(json);
        return this.deleteIndex(graphName, indexName);
    }

    /**
     * DELETE http://host/graph/indices/indexName
     * graph.dropIndex(indexName);
     * 

* DELETE http://host/graph/indices/indexName?key=key1&value=value1&id=id1 * Index index = graph.getIndex(indexName,...) * index.remove(key, value, graph.getVertex(id1)); */ @DELETE @Path("/{indexName}") @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON}) @Timed(name = "http.rest.indices.object.delete", absolute = true) public Response deleteIndex(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName) { String key = null; Object value = null; String id = null; final JSONObject theRequestObject = this.getRequestObject(); Object temp = theRequestObject.opt(Tokens.KEY); if (null != temp) key = temp.toString(); temp = theRequestObject.opt(Tokens.VALUE); if (null != temp) value = ElementHelper.getTypedPropertyValue(temp.toString()); temp = theRequestObject.opt(Tokens.ID); if (null != temp) id = temp.toString(); final Index index = this.getIndexFromGraph(graphName, indexName); final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName); final IndexableGraph graph = (IndexableGraph) rag.getGraph(); if (null == index) { final String msg = "Could not find index [" + indexName + "] on graph [" + graphName + "]"; logger.info(msg); final JSONObject error = generateErrorObject(msg); throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).entity(error).build()); } if (key == null && value == null && id == null) { try { graph.dropIndex(indexName); rag.tryCommit(); } catch (Exception ex) { logger.error(ex); rag.tryRollback(); final JSONObject error = generateErrorObjectJsonFail(ex); throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build()); } } else if (null != index & key != null && value != null && id != null) { try { if (index.getIndexClass().equals(Vertex.class)) index.remove(key, value, graph.getVertex(id)); else index.remove(key, value, graph.getEdge(id)); 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()); } } else { final String msg = "A key, value, id, and type (vertex/edge) must be provided to lookup elements in an index"; logger.info(msg); final JSONObject error = generateErrorObject(msg); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } return Response.ok(this.resultObject).build(); } @POST @Path("/{indexName}") @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON}) @Consumes({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON}) @Timed(name = "http.rest.indices.object.post", absolute = true) public Response postIndex(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName, final JSONObject json) { // initializes the request object with the data POSTed to the resource. URI parameters // will then be ignored when the getRequestObject is called as the request object will // have already been established. this.setRequestObject(json); return this.postIndex(graphName, indexName); } @POST @Path("/{indexName}") @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON}) @Timed(name = "http.rest.indices.object.post", absolute = true) public Response postIndex(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName) { String clazz = null; Set keys = null; Parameter[] indexParameters = new Parameter[0]; final JSONObject theRequestObject = this.getRequestObject(); Object temp = theRequestObject.opt(Tokens.CLASS); if (temp != null) clazz = temp.toString(); temp = theRequestObject.opt(Tokens.KEYS); if (temp != null) { try { final JSONArray ks; if (temp instanceof String) { ks = new JSONArray(); ks.put(temp); } else { ks = (JSONArray) temp; } keys = new HashSet(); for (int i = 0; i < ks.length(); i++) { keys.add(ks.getString(i)); } } catch (Exception e) { final JSONObject error = generateErrorObject("Index keys must be in an array: " + temp); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } } temp = theRequestObject.opt("params"); if (temp != null) { final JSONObject idxParamsJson = (JSONObject) temp; final ArrayList> idxParamsList = new ArrayList>(); final Iterator idxParamKeys = idxParamsJson.keys(); while (idxParamKeys.hasNext()) { final String nextIdxParamKey = (String) idxParamKeys.next(); idxParamsList.add(new Parameter(nextIdxParamKey, idxParamsJson.optString(nextIdxParamKey))); } indexParameters = new Parameter[idxParamsList.size()]; idxParamsList.toArray(indexParameters); } final Index index = this.getIndexFromGraph(graphName, indexName); final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName); final IndexableGraph graph = (IndexableGraph) rag.getGraph(); if (null != index) { final String msg = "Index [" + indexName + "] on graph [" + graphName + "] already exists"; logger.info(msg); final JSONObject error = generateErrorObject(msg); throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build()); } else { // create an index if (null != clazz) { final Class c; if (clazz.equals(Tokens.VERTEX)) c = Vertex.class; else if (clazz.equals(Tokens.EDGE)) c = Edge.class; else { final JSONObject error = generateErrorObject("Index class must be either vertex or edge"); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } final Index newIndex; try { newIndex = graph.createIndex(indexName, c, indexParameters); rag.tryCommit(); } catch (Exception e) { logger.info(e.getMessage()); rag.tryRollback(); final JSONObject error = generateErrorObject(e.getMessage()); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } try { this.resultObject.put(Tokens.QUERY_TIME, this.sh.stopWatch()); this.resultObject.put(Tokens.RESULTS, createJSONObject(newIndex)); } catch (JSONException ex) { logger.error(ex); final JSONObject error = generateErrorObjectJsonFail(ex); throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build()); } } else { final String msg = "Class (vertex/edge) must be provided to create a new index"; logger.info(msg); final JSONObject error = generateErrorObject(msg); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } } return Response.ok(this.resultObject).build(); } /** * PUT http://host/graph/indices/indexName?key=key1&value=value1&class=vertex&id=id1 */ @PUT @Path("/{indexName}") @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON}) @Consumes({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON}) @Timed(name = "http.rest.indices.object.put", absolute = true) public Response putElementInIndex(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName, final JSONObject json) { // initializes the request object with the data POSTed to the resource. URI parameters // will then be ignored when the getRequestObject is called as the request object will // have already been established. this.setRequestObject(json); return this.putElementInIndex(graphName, indexName); } /** * PUT http://host/graph/indices/indexName?key=key1&value=value1&class=vertex&id=id1 */ @PUT @Path("/{indexName}") @Produces({MediaType.APPLICATION_JSON, RexsterMediaType.APPLICATION_REXSTER_JSON, RexsterMediaType.APPLICATION_REXSTER_TYPED_JSON}) @Timed(name = "http.rest.indices.object.put", absolute = true) public Response putElementInIndex(@PathParam("graphname") final String graphName, @PathParam("indexName") final String indexName) { final Index index = this.getIndexFromGraph(graphName, indexName); final RexsterApplicationGraph rag = this.getRexsterApplicationGraph(graphName); final IndexableGraph graph = (IndexableGraph) rag.getGraph(); if (index == null) { JSONObject error = generateErrorObject("Index not found."); throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).entity(error).build()); } String key = null; Object value = null; String id = null; final JSONObject theRequestObject = this.getRequestObject(); Object temp = theRequestObject.opt(Tokens.KEY); if (null != temp) key = temp.toString(); temp = theRequestObject.opt(Tokens.VALUE); if (null != temp) value = ElementHelper.getTypedPropertyValue(temp.toString()); temp = theRequestObject.opt(Tokens.ID); if (null != temp) id = temp.toString(); if (key != null && value != null && id != null) { try { if (Vertex.class.isAssignableFrom(index.getIndexClass())) { index.put(key, value, graph.getVertex(id)); rag.tryCommit(); } else if (Edge.class.isAssignableFrom(index.getIndexClass())) { index.put(key, value, graph.getEdge(id)); rag.tryCommit(); } else { rag.tryRollback(); final JSONObject error = generateErrorObject("Index class must be either vertex or edge"); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } 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()); } } else { final String msg = "A key, value, and id must be provided to add elements to an index"; logger.info(msg); final JSONObject error = generateErrorObject(msg); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } return Response.ok(this.resultObject).build(); } private static JSONObject createJSONObject(final Index index) { final Map mapIndex = new HashMap(); mapIndex.put("name", index.getIndexName()); if (Vertex.class.isAssignableFrom(index.getIndexClass())) { mapIndex.put("class", "vertex"); } else if (Edge.class.isAssignableFrom(index.getIndexClass())) { mapIndex.put("class", "edge"); } return new JSONObject(mapIndex); } private Index getIndexFromGraph(final String graphName, final String name) { final Graph graph = this.getRexsterApplicationGraph(graphName).getUnwrappedGraph(); final IndexableGraph idxGraph = graph instanceof IndexableGraph ? (IndexableGraph) 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()); } final Iterable> indices = idxGraph.getIndices(); for (final Index index : indices) { if (index.getIndexName().equals(name)) { return index; } } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy