package eu.fbk.knowledgestore.server.http.jaxrs; import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.HttpMethod; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import com.google.common.collect.Sets; import org.codehaus.enunciate.jaxrs.TypeHint; import org.openrdf.model.URI; import eu.fbk.knowledgestore.Operation; import eu.fbk.knowledgestore.OperationException; import eu.fbk.knowledgestore.Outcome; import eu.fbk.knowledgestore.data.Data; import eu.fbk.knowledgestore.data.Stream; import eu.fbk.knowledgestore.internal.jaxrs.Protocol; import eu.fbk.knowledgestore.internal.rdf.RDFUtil; /** * Provides the KnowledgeStore SPARQL endpoint. * <p style="color: red"> * DOCUMENTATION COMING SOON * </p> */ @Path("/" + Protocol.PATH_SPARQL) public class Sparql extends Resource { @GET @Produces(Protocol.MIME_TYPES_ALL) @TypeHint(Stream.class) public Response get( @QueryParam(Protocol.PARAMETER_DEFAULT_GRAPH) final List<String> defaultGraphs, @QueryParam(Protocol.PARAMETER_NAMED_GRAPH) final List<String> namedGraphs, @QueryParam(Protocol.PARAMETER_QUERY) final String query) throws OperationException { return query(query, defaultGraphs, namedGraphs); } @POST @Consumes("application/x-www-form-urlencoded") @Produces(Protocol.MIME_TYPES_ALL) @TypeHint(Stream.class) public Response postURLencoded( @FormParam(Protocol.PARAMETER_DEFAULT_GRAPH) final List<String> defaultGraphs, @FormParam(Protocol.PARAMETER_NAMED_GRAPH) final List<String> namedGraphs, @FormParam(Protocol.PARAMETER_QUERY) final String query) throws OperationException { return query(query, defaultGraphs, namedGraphs); } @POST @Consumes("application/sparql-query") @Produces(Protocol.MIME_TYPES_ALL) @TypeHint(Stream.class) public Response postDirect( @QueryParam(Protocol.PARAMETER_DEFAULT_GRAPH) final List<String> defaultGraphs, @QueryParam(Protocol.PARAMETER_NAMED_GRAPH) final List<String> namedGraphs, final String query) throws OperationException { return query(query, defaultGraphs, namedGraphs); } private Response query(final String query, final List<String> defaultGraphs, final List<String> namedGraphs) throws OperationException { // Check mandatory parameter checkNotNull(query, Outcome.Status.ERROR_INVALID_INPUT, "Missing query"); // Prepare the SPARQL operation, returning an error if parameters are wrong final String form; final Operation.Sparql operation; try { form = RDFUtil.detectSparqlForm(query); operation = getSession().sparql(query) // .timeout(getTimeout()) // .defaultGraphs(parseGraphURIs(defaultGraphs)) // .namedGraphs(parseGraphURIs(namedGraphs)); } catch (final RuntimeException ex) { throw new OperationException(newOutcome(Outcome.Status.ERROR_INVALID_INPUT, "%s", ex.getMessage()), ex); } // Select correct MIME type via negotiation, validate preconditions and handle probes final GenericType<?> type; if (form.equals("construct") || form.equals("describe")) { init(false, Protocol.MIME_TYPES_RDF, null, null); type = Protocol.STREAM_OF_STATEMENTS; } else if (form.equals("select")) { init(false, Protocol.MIME_TYPES_SPARQL_TUPLE, null, null); type = Protocol.STREAM_OF_TUPLES; } else { init(false, Protocol.MIME_TYPES_SPARQL_BOOLEAN, null, null); type = Protocol.STREAM_OF_BOOLEANS; } // Setup the result stream based on the selected type. Note that an empty result is // selected for HEAD methods, as only headers will be returned. Stream<?> entity; if (getMethod().equals(HttpMethod.HEAD)) { entity = Stream.create(); } else if (type == Protocol.STREAM_OF_STATEMENTS) { entity = operation.execTriples(); } else if (type == Protocol.STREAM_OF_TUPLES) { entity = operation.execTuples(); } else if (type == Protocol.STREAM_OF_BOOLEANS) { entity = Stream.create(operation.execBoolean()); } else { throw new Error("Unexpected type: " + type); } // Build and return the SPARQL response return newResponseBuilder(Status.OK, closeOnCompletion(entity), type).build(); } private static Set<URI> parseGraphURIs(final List<String> strings) { if (strings == null || strings.isEmpty()) { return null; } final Set<URI> uris = Sets.newHashSetWithExpectedSize(strings.size()); for (final String string : strings) { uris.add(Data.getValueFactory().createURI(string)); } return uris; } }