Skip to content

Commit

Permalink
Add form request (application/x-www-form-urlencoded) support for spar…
Browse files Browse the repository at this point in the history
…ql end point

- Refactor the rest api codes for sparql

Resolves: https://www.pivotaltracker.com/story/show/72619228
  • Loading branch information
lsitu authored and Andrew Woods committed Jul 25, 2014
1 parent db1ac82 commit 2398042
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 7 deletions.
Expand Up @@ -16,6 +16,7 @@
package org.fcrepo.transform.http;

import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Strings;
import com.hp.hpl.jena.query.ResultSet;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
Expand All @@ -34,10 +35,10 @@
import org.slf4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
Expand All @@ -60,13 +61,15 @@
import static com.google.common.util.concurrent.Futures.addCallback;
import static javax.ws.rs.core.MediaType.TEXT_HTML;
import static javax.ws.rs.core.Response.ok;
import static javax.ws.rs.core.Response.status;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static org.apache.jena.riot.WebContent.contentTypeN3;
import static org.apache.jena.riot.WebContent.contentTypeNTriples;
import static org.apache.jena.riot.WebContent.contentTypeRDFXML;
import static org.apache.jena.riot.WebContent.contentTypeResultsBIO;
import static org.apache.jena.riot.WebContent.contentTypeResultsJSON;
import static org.apache.jena.riot.WebContent.contentTypeResultsXML;
import static org.apache.jena.riot.WebContent.contentTypeSPARQLQuery;
import static org.apache.jena.riot.WebContent.contentTypeHTMLForm;
import static org.apache.jena.riot.WebContent.contentTypeSSE;
import static org.apache.jena.riot.WebContent.contentTypeTextCSV;
import static org.apache.jena.riot.WebContent.contentTypeTextPlain;
Expand All @@ -82,6 +85,7 @@
* Primitive SPARQL JAX-RS endpoint
*
* @author cabeer
* @author lsitu
*/
@Component
@Scope("prototype")
Expand Down Expand Up @@ -146,7 +150,6 @@ public void write(final OutputStream output) throws IOException {
* @throws RepositoryException
*/
@POST
@Consumes({contentTypeSPARQLQuery})
@Produces({contentTypeTextTSV, contentTypeTextCSV, contentTypeSSE,
contentTypeTextPlain, contentTypeResultsJSON,
contentTypeResultsXML, contentTypeResultsBIO, contentTypeTurtle,
Expand All @@ -162,17 +165,54 @@ public Response runSparqlQuery(final InputStream requestBodyStream,

final String sparqlQuery = IOUtils.toString(requestBodyStream);

LOGGER.trace("Running SPARQL query: {}", sparqlQuery);
return rexecSparql(sparqlQuery, bestPossibleResponse, graphSubjects);
}

/**
* Execute a SPARQL query against the JCR index
* @param query
* @param request
* @param uriInfo
* @return SPARQL query results
* @throws IOException
* @throws RepositoryException
*/
@POST
@Consumes({contentTypeHTMLForm})
@Produces({contentTypeTextTSV, contentTypeTextCSV, contentTypeSSE,
contentTypeTextPlain, contentTypeResultsJSON,
contentTypeResultsXML, contentTypeResultsBIO, contentTypeTurtle,
contentTypeN3, contentTypeNTriples, contentTypeRDFXML})
public Response runSparqlQuery(@FormParam("query") final String query,
@Context final Request request,
@Context final UriInfo uriInfo)
throws IOException, RepositoryException {

LOGGER.trace("POST SPARQL query with {}: {}", contentTypeHTMLForm, query);
if (Strings.isNullOrEmpty(query)) {
return status(BAD_REQUEST)
.entity("SPARQL must not be null. Please submit a query with parameter 'query'.")
.build();
}
return rexecSparql(query,
request.selectVariant(POSSIBLE_SPARQL_RDF_VARIANTS),
new HttpIdentifierTranslator(session, FedoraNodes.class, uriInfo));
}

private Response rexecSparql(final String sparql,
final Variant bestPossibleResponse,
final IdentifierTranslator graphSubjects)
throws RepositoryException {
LOGGER.trace("Running SPARQL query: {}", sparql);

final JQLConverter jqlConverter = new JQLConverter(session, graphSubjects, sparqlQuery);
final JQLConverter jqlConverter = new JQLConverter(session, graphSubjects, sparql);

LOGGER.trace("Converted to JQL query: {}", jqlConverter.getStatement());

final ResultSet resultSet = jqlConverter.execute();

final ResultSetStreamingOutput streamingOutput =
new ResultSetStreamingOutput(resultSet, bestPossibleResponse
.getMediaType());
new ResultSetStreamingOutput(resultSet, bestPossibleResponse.getMediaType());

addCallback(streamingOutput, new LogoutCallback(session));

Expand Down
Expand Up @@ -19,10 +19,13 @@
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFactory;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.fcrepo.integration.AbstractResourceIT;
import org.fcrepo.kernel.impl.FedoraResourceImpl;
Expand All @@ -32,14 +35,19 @@
import org.modeshape.jcr.api.JcrConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import static org.apache.jena.riot.WebContent.contentTypeHTMLForm;

import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.ws.rs.core.Response.Status;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -211,4 +219,125 @@ private String getResponseContent(final String sparql) throws IOException {
logger.trace("Retrieved sparql feed:\n" + content);
return content;
}


private String getFormRequestResponseContent(final String sparql)
throws IOException {
final HttpPost request = getFormRequest (sparql, "query");

final HttpResponse response = client.execute(request);
assertEquals(200, response.getStatusLine().getStatusCode());

final String content = EntityUtils.toString(response.getEntity());
logger.trace("Retrieved sparql feed:\n" + content);
return content;
}

private HttpPost getFormRequest (final String sparql, final String paramName)
throws UnsupportedEncodingException {
final HttpPost post = new HttpPost(serverAddress + "/fcr:sparql");
post.addHeader("Content-Type", contentTypeHTMLForm);
final List<BasicNameValuePair> nvps = new ArrayList<>();
if (sparql != null) {
nvps.add(new BasicNameValuePair(
paramName != null && paramName.length() > 0 ? paramName : "sparql", sparql));
}

final HttpEntity formEntity = new UrlEncodedFormEntity(nvps, "UTF-8");
post.setEntity(formEntity);
return post;
}

@Test
public void formRequestShouldWorkWithSimpleProperties() throws IOException {

final String sparql = "PREFIX dc: <http://purl.org/dc/elements/1.1/> " +
"SELECT ?subject WHERE { ?subject dc:title \"xyz\"}";

final String content = getFormRequestResponseContent(sparql);
final ResultSet resultSet = ResultSetFactory.fromTSV(IOUtils.toInputStream(content));


assertTrue(resultSet.hasNext());

assertEquals("subject", resultSet.getResultVars().get(0));

assertEquals(serverAddress + "/abc", resultSet.next().get("subject").toString());
}

@Test
public void formRequestShouldWorkWithRdfTypeMixins() throws IOException {

final String sparql =
"PREFIX dc: <http://purl.org/dc/elements/1.1/> SELECT " +
"?subject WHERE { " +
"?subject a <http://fedora.info/definitions/v4/rest-api#resource> . ?subject dc:title \"xyz\"}";

final String content = getFormRequestResponseContent(sparql);
final ResultSet resultSet = ResultSetFactory.fromTSV(IOUtils.toInputStream(content));


assertTrue(resultSet.hasNext());

assertEquals("subject", resultSet.getResultVars().get(0));

assertEquals(serverAddress + "/abc", resultSet.next().get("subject").toString());

}

@Test
public void formRequestShouldWorkWithReferenceProperties() throws IOException {

final String sparql =
"PREFIX fedorarelsext: <http://fedora.info/definitions/v4/rels-ext#> SELECT " +
"?subject ?part WHERE { ?subject fedorarelsext:hasPart ?part }";

final String content = getFormRequestResponseContent(sparql);
final ResultSet resultSet = ResultSetFactory.fromTSV(IOUtils.toInputStream(content));


assertTrue(resultSet.hasNext());

assertEquals("subject", resultSet.getResultVars().get(0));

final QuerySolution row = resultSet.next();
assertEquals(serverAddress + "/abc", row.get("subject").toString());
assertEquals(serverAddress + "/xyz", row.get("part").toString());
}

@Test
public void formRequestShouldWorkWithJoinedQueries() throws IOException {

final String sparql = "PREFIX fedorarelsext: <http://fedora.info/definitions/v4/rels-ext#>\n" +
"PREFIX dc: <http://purl.org/dc/elements/1.1/>\n" +
"SELECT ?part ?collectionTitle WHERE { ?part fedorarelsext:isPartOf ?collection .\n" +
" ?collection dc:title ?collectionTitle }";

final String content = getFormRequestResponseContent(sparql);
final ResultSet resultSet = ResultSetFactory.fromTSV(IOUtils.toInputStream(content));


assertTrue(resultSet.hasNext());

assertEquals("part", resultSet.getResultVars().get(0));

final QuerySolution row = resultSet.next();
assertEquals(serverAddress + "/xyz", row.get("part").toString());
assertEquals("xyz", row.get("collectionTitle").asLiteral().getLexicalForm());
}

@Test
public void testBadFormRequest() throws IOException {

String sparql = "";

HttpPost badRequest = getFormRequest(sparql, null);
HttpResponse response = client.execute(badRequest);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusLine().getStatusCode());

sparql = null;
badRequest = getFormRequest(sparql, null);
response = client.execute(badRequest);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusLine().getStatusCode());
}
}

0 comments on commit 2398042

Please sign in to comment.