From e198fce9084eb732db6cd92b02c20e0f4c1334d2 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 27 May 2020 22:58:20 -0600 Subject: [PATCH] [VIVO-1872] - Add download option to SPARQL Query page (#164) * Add download option to SPARQL Query page * Set SPARQL query results content type even if downloading * Address pull request comments --- .../admin/SparqlQueryController.java | 30 +++++++++++++++++-- .../api/sparqlquery/RdfResultMediaType.java | 24 ++++++++++----- .../api/sparqlquery/ResultSetMediaType.java | 22 ++++++++++---- .../body/admin/admin-sparqlQueryForm.ftl | 5 ++++ 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java index 6166d1cf9..096263dab 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java @@ -40,6 +40,8 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; import edu.cornell.mannlib.vitro.webapp.utils.http.AcceptHeaderParsingException; import edu.cornell.mannlib.vitro.webapp.utils.http.NotAcceptableException; import edu.cornell.mannlib.vitro.webapp.utils.sparql.SparqlQueryUtils; +import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.RdfResultMediaType; +import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.ResultSetMediaType; /** * Present the SPARQL Query form, and execute the queries. @@ -110,11 +112,20 @@ public class SparqlQueryController extends FreemarkerHttpServlet { .getRDFService(); String queryString = req.getParameter("query"); + boolean download = Boolean.parseBoolean(req.getParameter("download")); + Query query = SparqlQueryUtils.create(queryString); try { - String format = interpretRequestedFormats(req, queryString); + String format = interpretRequestedFormats(req, query); SparqlQueryApiExecutor core = SparqlQueryApiExecutor.instance( rdfService, queryString, format); resp.setContentType(core.getMediaType()); + + if (download) { + String extension = getFilenameExtension(req, query, format); + resp.setHeader("Content-Transfer-Encoding", "binary"); + resp.setHeader("Content-disposition", "attachment; filename=query-results." + extension); + } + core.executeAndFormat(resp.getOutputStream()); } catch (InvalidQueryTypeException e) { do400BadRequest("Query type is not SELECT, ASK, CONSTRUCT, " @@ -132,8 +143,7 @@ public class SparqlQueryController extends FreemarkerHttpServlet { } private String interpretRequestedFormats(HttpServletRequest req, - String queryString) throws NotAcceptableException { - Query query = SparqlQueryUtils.create(queryString); + Query query) throws NotAcceptableException { String parameterName = (query.isSelectType() || query.isAskType()) ? "resultFormat" : "rdfResultFormat"; String parameterValue = req.getParameter(parameterName); @@ -145,6 +155,20 @@ public class SparqlQueryController extends FreemarkerHttpServlet { } } + private String getFilenameExtension(HttpServletRequest req, + Query query, String format) { + String extension; + if (query.isSelectType() || query.isAskType()) { + ResultSetMediaType mediaType = ResultSetMediaType.fromContentType(format); + extension = mediaType.getExtension(); + } + else { + RdfResultMediaType mediaType = RdfResultMediaType.fromContentType(format); + extension = mediaType.getExtension(); + } + return extension; + } + private void do400BadRequest(String message, HttpServletResponse resp) throws IOException { resp.setStatus(400); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/RdfResultMediaType.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/RdfResultMediaType.java index 03ffcd93a..3812bf43e 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/RdfResultMediaType.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/RdfResultMediaType.java @@ -12,17 +12,17 @@ import java.util.Map; * and DESCRIBE). */ public enum RdfResultMediaType { - TEXT("text/plain", true, "NTRIPLE", "N-TRIPLE"), + TEXT("text/plain", true, "NTRIPLE", "N-TRIPLE", "nt"), - RDF_XML("application/rdf+xml", true, "RDFXML", "RDF/XML"), + RDF_XML("application/rdf+xml", true, "RDFXML", "RDF/XML", "rdf"), - N3("text/n3", true, "N3", "N3"), + N3("text/n3", true, "N3", "N3", "n3"), - TTL("text/turtle", false, "N3", "TTL"), + TTL("text/turtle", false, "N3", "TTL", "ttl"), - JSON("application/json", false, "N3", "JSON"), + JSON("application/json", false, "N3", "JSON", "json"), - JSON_LD("application/ld+json", false, "N3", "JSON"); + JSON_LD("application/ld+json", false, "N3", "JSON", "jsonld"); // ---------------------------------------------------------------------- // Keep a map of content types, for easy conversion back and forth @@ -79,12 +79,18 @@ public enum RdfResultMediaType { */ private final String jenaResponseFormat; + /** + * What extension should be used if file is downloaded? + */ + private final String extension; + private RdfResultMediaType(String contentType, boolean nativeFormat, - String serializationFormat, String jenaResponseFormat) { + String serializationFormat, String jenaResponseFormat, String extension) { this.contentType = contentType; this.nativeFormat = nativeFormat; this.serializationFormat = serializationFormat; this.jenaResponseFormat = jenaResponseFormat; + this.extension = extension; } public String getContentType() { @@ -103,4 +109,8 @@ public enum RdfResultMediaType { return jenaResponseFormat; } + public String getExtension() { + return extension; + } + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/ResultSetMediaType.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/ResultSetMediaType.java index b283d84fe..5aa424f14 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/ResultSetMediaType.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/api/sparqlquery/ResultSetMediaType.java @@ -12,15 +12,15 @@ import java.util.Map; * SELECT and ASK). */ public enum ResultSetMediaType { - TEXT("text/plain", true, "TEXT", null), + TEXT("text/plain", true, "TEXT", null, "txt"), - CSV("text/csv", true, "CSV", null), + CSV("text/csv", true, "CSV", null, "csv"), - TSV("text/tab-separated-values", false, "CSV", "tsv"), + TSV("text/tab-separated-values", false, "CSV", "tsv", "tsv"), - XML("application/sparql-results+xml", true, "XML", null), + XML("application/sparql-results+xml", true, "XML", null, "xml"), - JSON("application/sparql-results+json", true, "JSON", null); + JSON("application/sparql-results+json", true, "JSON", null, "json"); // ---------------------------------------------------------------------- // Keep a map of content types, for easy conversion back and forth @@ -78,12 +78,18 @@ public enum ResultSetMediaType { */ private final String jenaResponseFormat; + /** + * What extension should be used if file is downloaded? + */ + private final String extension; + private ResultSetMediaType(String contentType, boolean nativeFormat, - String rdfServiceFormat, String jenaResponseFormat) { + String rdfServiceFormat, String jenaResponseFormat, String extension) { this.contentType = contentType; this.nativeFormat = nativeFormat; this.rdfServiceFormat = rdfServiceFormat; this.jenaResponseFormat = jenaResponseFormat; + this.extension = extension; } public String getContentType() { @@ -102,4 +108,8 @@ public enum ResultSetMediaType { return jenaResponseFormat; } + public String getExtension() { + return extension; + } + } diff --git a/webapp/src/main/webapp/templates/freemarker/body/admin/admin-sparqlQueryForm.ftl b/webapp/src/main/webapp/templates/freemarker/body/admin/admin-sparqlQueryForm.ftl index d9e72f390..dc356e970 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/admin/admin-sparqlQueryForm.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/admin/admin-sparqlQueryForm.ftl @@ -27,6 +27,11 @@ +
+ +
+
+