Package com.tinkerpop.rexster

Source Code of com.tinkerpop.rexster.IndexResource

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<String> returnKeys = RequestObjectHelper.getReturnKeys(theRequestObject);
        final GraphSONMode mode = showTypes ? GraphSONMode.EXTENDED : GraphSONMode.NORMAL;

        long counter = 0l;

        if (null != index && key != null && value != null) {
            final CloseableIterable<Element> indexElements = (CloseableIterable<Element>) 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);
     * <p/>
     * 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<String> 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<String>();
                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<Parameter<Object, Object>> idxParamsList = new ArrayList<Parameter<Object, Object>>();

            final Iterator idxParamKeys = idxParamsJson.keys();
            while (idxParamKeys.hasNext()) {
                final String nextIdxParamKey = (String) idxParamKeys.next();
                idxParamsList.add(new Parameter<Object, Object>(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<String, String> mapIndex = new HashMap<String, String>();
        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<Index<? extends Element>> indices = idxGraph.getIndices();
        for (final Index index : indices) {
            if (index.getIndexName().equals(name)) {
                return index;
            }
        }

        return null;
    }

}
TOP

Related Classes of com.tinkerpop.rexster.IndexResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.