VIVO-731 Replace SparqlQueryServlet with SparqlQueryController
SparqlQueryServlet was JSP-based, so delete the JSP also. SparqlQueryController is Freemarker-based, and is a this shell around the SparqlQueryApiExecutor.
This commit is contained in:
parent
0c0915ef65
commit
de32d53791
7 changed files with 264 additions and 1560 deletions
|
@ -1,476 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.github.jsonldjava.core.JSONLD;
|
||||
import com.github.jsonldjava.core.JSONLDProcessingError;
|
||||
import com.github.jsonldjava.impl.JenaRDFParser;
|
||||
import com.github.jsonldjava.utils.JSONUtils;
|
||||
import com.hp.hpl.jena.query.Query;
|
||||
import com.hp.hpl.jena.query.QuerySolution;
|
||||
import com.hp.hpl.jena.query.ResultSet;
|
||||
import com.hp.hpl.jena.query.ResultSetFactory;
|
||||
import com.hp.hpl.jena.query.ResultSetFormatter;
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.sparql.resultset.ResultSetFormat;
|
||||
import com.hp.hpl.jena.vocabulary.XSD;
|
||||
|
||||
import edu.cornell.mannlib.vedit.controller.BaseEditController;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Ontology;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ResultFormat;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.SparqlQueryUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.ContentType;
|
||||
|
||||
|
||||
/**
|
||||
* Services a SPARQL query. This will return a simple error message and a 501 if
|
||||
* there is no Model.
|
||||
*
|
||||
*
|
||||
* @author bdc34
|
||||
*
|
||||
*/
|
||||
public class SparqlQueryServlet extends BaseEditController {
|
||||
private static final Log log = LogFactory.getLog(SparqlQueryServlet.class.getName());
|
||||
|
||||
/**
|
||||
* format configurations for SELECT queries.
|
||||
*/
|
||||
protected static HashMap<String,RSFormatConfig> rsFormats = new HashMap<String,RSFormatConfig>();
|
||||
|
||||
/**
|
||||
* format configurations for CONSTRUCT/DESCRIBE queries.
|
||||
*/
|
||||
protected static HashMap<String,ModelFormatConfig> modelFormats =
|
||||
new HashMap<String,ModelFormatConfig>();
|
||||
|
||||
/**
|
||||
* Use this map to decide which MIME type is suited for the "accept" header.
|
||||
*/
|
||||
public static final Map<String, Float> ACCEPTED_CONTENT_TYPES;
|
||||
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.doGet(request,response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
VitroRequest vreq = new VitroRequest(request);
|
||||
|
||||
//first check if the email and password are just in the request
|
||||
String email = vreq.getParameter("email");
|
||||
String password = vreq.getParameter("password");
|
||||
boolean isAuth = PolicyHelper.isAuthorizedForActions(vreq,
|
||||
email, password, SimplePermission.USE_SPARQL_QUERY_PAGE.ACTIONS);
|
||||
|
||||
//otherwise use the normal auth mechanism
|
||||
if( ! isAuth &&
|
||||
!isAuthorizedToDisplayPage(request, response,
|
||||
SimplePermission.USE_SPARQL_QUERY_PAGE.ACTIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Model model = vreq.getJenaOntModel();
|
||||
if( model == null ){
|
||||
doNoModelInContext(response);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use RDFService from context to avoid language filtering
|
||||
RDFService rdfService = RDFServiceUtils.getRDFServiceFactory(
|
||||
getServletContext()).getRDFService();
|
||||
|
||||
String queryParam = vreq.getParameter("query");
|
||||
log.debug("queryParam was : " + queryParam);
|
||||
|
||||
if( queryParam == null || "".equals(queryParam) ){
|
||||
doHelp(request,response);
|
||||
return;
|
||||
}
|
||||
|
||||
String contentType = checkForContentType(vreq.getHeader("Accept"));
|
||||
|
||||
Query query = SparqlQueryUtils.create(queryParam);
|
||||
if( query.isSelectType() ){
|
||||
String format = contentType!=null ? contentType:vreq.getParameter("resultFormat");
|
||||
RSFormatConfig formatConf = rsFormats.get(format);
|
||||
doSelect(response, queryParam, formatConf, rdfService);
|
||||
}else if( query.isAskType()){
|
||||
doAsk( queryParam, rdfService, response );
|
||||
}else if( query.isConstructType() || query.isDescribeType() ){
|
||||
String format = contentType != null ? contentType : vreq.getParameter("rdfResultFormat");
|
||||
if (format== null) {
|
||||
format= "RDF/XML-ABBREV";
|
||||
}
|
||||
ModelFormatConfig formatConf = modelFormats.get(format);
|
||||
doConstruct(response, query, formatConf, rdfService);
|
||||
}else{
|
||||
doHelp(request,response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
private void doAsk(String queryParam, RDFService rdfService,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
|
||||
// Irrespective of the ResultFormatParam,
|
||||
// this always prints a boolean to the default OutputStream.
|
||||
String result;
|
||||
try {
|
||||
result = (rdfService.sparqlAskQuery(queryParam) == true)
|
||||
? "true"
|
||||
: "false";
|
||||
} catch (RDFServiceException e) {
|
||||
throw new ServletException( "Could not execute ask query ", e );
|
||||
}
|
||||
PrintWriter p = response.getWriter();
|
||||
p.write(result);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query and send the result to out. Attempt to
|
||||
* send the RDFService the same format as the rdfResultFormatParam
|
||||
* so that the results from the RDFService can be directly piped to the client.
|
||||
*/
|
||||
private void doSelect(HttpServletResponse response,
|
||||
String queryParam,
|
||||
RSFormatConfig formatConf,
|
||||
RDFService rdfService
|
||||
) throws ServletException {
|
||||
try {
|
||||
if( ! formatConf.converstionFromWireFormat ){
|
||||
response.setContentType( formatConf.responseMimeType );
|
||||
InputStream results;
|
||||
results = rdfService.sparqlSelectQuery(queryParam, formatConf.wireFormat );
|
||||
pipe( results, response.getOutputStream() );
|
||||
}else{
|
||||
//always use JSON when conversion is needed.
|
||||
InputStream results = rdfService.sparqlSelectQuery(queryParam, ResultFormat.JSON );
|
||||
|
||||
response.setContentType( formatConf.responseMimeType );
|
||||
|
||||
ResultSet rs = ResultSetFactory.fromJSON( results );
|
||||
OutputStream out = response.getOutputStream();
|
||||
ResultSetFormatter.output(out, rs, formatConf.jenaResponseFormat);
|
||||
}
|
||||
} catch (RDFServiceException e) {
|
||||
throw new ServletException("Cannot get result from the RDFService",e);
|
||||
} catch (IOException e) {
|
||||
throw new ServletException("Cannot perform SPARQL SELECT",e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute the query and send the result to out. Attempt to
|
||||
* send the RDFService the same format as the rdfResultFormatParam
|
||||
* so that the results from the RDFService can be directly piped to the client.
|
||||
* @param rdfService
|
||||
* @throws IOException
|
||||
* @throws RDFServiceException
|
||||
* @throws
|
||||
*/
|
||||
private void doConstruct( HttpServletResponse response,
|
||||
Query query,
|
||||
ModelFormatConfig formatConfig,
|
||||
RDFService rdfService
|
||||
) throws ServletException{
|
||||
try{
|
||||
InputStream rawResult = null;
|
||||
if( query.isConstructType() ){
|
||||
rawResult= rdfService.sparqlConstructQuery( query.toString(), formatConfig.wireFormat );
|
||||
}else if ( query.isDescribeType() ){
|
||||
rawResult = rdfService.sparqlDescribeQuery( query.toString(), formatConfig.wireFormat );
|
||||
}
|
||||
|
||||
response.setContentType( formatConfig.responseMimeType );
|
||||
|
||||
if( formatConfig.converstionFromWireFormat ){
|
||||
Model resultModel = RDFServiceUtils.parseModel( rawResult, formatConfig.wireFormat );
|
||||
if( "JSON-LD".equals( formatConfig.jenaResponseFormat )){
|
||||
//since jena 2.6.4 doesn't support JSON-LD we do it
|
||||
try {
|
||||
JenaRDFParser parser = new JenaRDFParser();
|
||||
Object json = JSONLD.fromRDF(resultModel, parser);
|
||||
JSONUtils.write(response.getWriter(), json);
|
||||
} catch (JSONLDProcessingError e) {
|
||||
throw new RDFServiceException("Could not convert from Jena model to JSON-LD", e);
|
||||
}
|
||||
}else{
|
||||
OutputStream out = response.getOutputStream();
|
||||
resultModel.write(out, formatConfig.jenaResponseFormat );
|
||||
}
|
||||
}else{
|
||||
OutputStream out = response.getOutputStream();
|
||||
pipe( rawResult, out );
|
||||
}
|
||||
}catch( IOException ex){
|
||||
throw new ServletException("could not run SPARQL CONSTRUCT",ex);
|
||||
} catch (RDFServiceException ex) {
|
||||
throw new ServletException("could not run SPARQL CONSTRUCT",ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void pipe( InputStream in, OutputStream out) throws IOException{
|
||||
int size;
|
||||
byte[] buffer = new byte[4096];
|
||||
while( (size = in.read(buffer)) > -1 ) {
|
||||
out.write(buffer,0,size);
|
||||
}
|
||||
}
|
||||
|
||||
private void doNoModelInContext(HttpServletResponse res){
|
||||
try {
|
||||
res.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED);
|
||||
ServletOutputStream sos = res.getOutputStream();
|
||||
sos.println("<html><body>this service is not supporeted by the current " +
|
||||
"webapp configuration. A jena model is required in the servlet context.</body></html>" );
|
||||
} catch (IOException e) {
|
||||
log.error("Could not write to ServletOutputStream");
|
||||
}
|
||||
}
|
||||
|
||||
private void toCsv(Writer out, ResultSet results) {
|
||||
// The Skife library wouldn't quote and escape the normal way,
|
||||
// so I'm trying it manually.
|
||||
List<String> varNames = results.getResultVars();
|
||||
int width = varNames.size();
|
||||
while (results.hasNext()) {
|
||||
QuerySolution solution = (QuerySolution) results.next();
|
||||
String[] valueArray = new String[width];
|
||||
Iterator<String> varNameIt = varNames.iterator();
|
||||
int index = 0;
|
||||
while (varNameIt.hasNext()) {
|
||||
String varName = varNameIt.next();
|
||||
String value = null;
|
||||
try {
|
||||
Literal lit = solution.getLiteral(varName);
|
||||
if (lit != null) {
|
||||
value = lit.getLexicalForm();
|
||||
if (XSD.anyURI.getURI().equals(lit.getDatatypeURI())) {
|
||||
value = URLDecoder.decode(value, "UTF-8");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
Resource res = solution.getResource(varName);
|
||||
if (res != null) {
|
||||
if (res.isAnon()) {
|
||||
value = res.getId().toString();
|
||||
} else {
|
||||
value = res.getURI();
|
||||
}
|
||||
}
|
||||
} catch (Exception f) {}
|
||||
}
|
||||
valueArray[index] = value;
|
||||
index++;
|
||||
}
|
||||
|
||||
StringBuffer rowBuff = new StringBuffer();
|
||||
for (int i = 0; i < valueArray.length; i++) {
|
||||
String value = valueArray[i];
|
||||
if (value != null) {
|
||||
value.replaceAll("\"", "\\\"");
|
||||
rowBuff.append("\"").append(value).append("\"");
|
||||
}
|
||||
if (i + 1 < width) {
|
||||
rowBuff.append(",");
|
||||
}
|
||||
}
|
||||
rowBuff.append("\n");
|
||||
try {
|
||||
out.write(rowBuff.toString());
|
||||
} catch (IOException ioe) {
|
||||
log.error(ioe);
|
||||
}
|
||||
}
|
||||
try {
|
||||
out.flush();
|
||||
} catch (IOException ioe) {
|
||||
log.error(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private void doHelp(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
|
||||
VitroRequest vreq = new VitroRequest(req);
|
||||
|
||||
OntologyDao daoObj = vreq.getUnfilteredWebappDaoFactory().getOntologyDao();
|
||||
List<Ontology> ontologiesObj = daoObj.getAllOntologies();
|
||||
ArrayList<String> prefixList = new ArrayList<String>();
|
||||
|
||||
if(ontologiesObj !=null && ontologiesObj.size()>0){
|
||||
for(Ontology ont: ontologiesObj) {
|
||||
prefixList.add(ont.getPrefix() == null ? "(not yet specified)" : ont.getPrefix());
|
||||
prefixList.add(ont.getURI() == null ? "" : ont.getURI());
|
||||
}
|
||||
}
|
||||
else{
|
||||
prefixList.add("<strong>" + "No Ontologies added" + "</strong>");
|
||||
prefixList.add("<strong>" + "Load Ontologies" + "</strong>");
|
||||
}
|
||||
|
||||
req.setAttribute("prefixList", prefixList);
|
||||
|
||||
req.setAttribute("title","SPARQL Query");
|
||||
req.setAttribute("bodyJsp", "/admin/sparqlquery/sparqlForm.jsp");
|
||||
|
||||
RequestDispatcher rd = req.getRequestDispatcher("/"+Controllers.BASIC_JSP);
|
||||
rd.forward(req,res);
|
||||
}
|
||||
|
||||
/** Simple boolean vaule to improve the legibility of confiugrations. */
|
||||
private final static boolean CONVERT = true;
|
||||
|
||||
/** Simple vaule to improve the legibility of confiugrations. */
|
||||
private final static String NO_CONVERSION = null;
|
||||
|
||||
public static class FormatConfig{
|
||||
public String valueFromForm;
|
||||
public boolean converstionFromWireFormat;
|
||||
public String responseMimeType;
|
||||
}
|
||||
|
||||
private static ModelFormatConfig[] fmts = {
|
||||
new ModelFormatConfig("RDF/XML",
|
||||
!CONVERT, ModelSerializationFormat.RDFXML, NO_CONVERSION, "application/rdf+xml" ),
|
||||
new ModelFormatConfig("RDF/XML-ABBREV",
|
||||
CONVERT, ModelSerializationFormat.N3, "RDF/XML-ABBREV", "application/rdf+xml" ),
|
||||
new ModelFormatConfig("N3",
|
||||
!CONVERT, ModelSerializationFormat.N3, NO_CONVERSION, "text/n3" ),
|
||||
new ModelFormatConfig("N-TRIPLE",
|
||||
!CONVERT, ModelSerializationFormat.NTRIPLE, NO_CONVERSION, "text/plain" ),
|
||||
new ModelFormatConfig("TTL",
|
||||
CONVERT, ModelSerializationFormat.N3, "TTL", "application/x-turtle" ),
|
||||
new ModelFormatConfig("JSON-LD",
|
||||
CONVERT, ModelSerializationFormat.N3, "JSON-LD", "application/javascript" ) };
|
||||
|
||||
public static class ModelFormatConfig extends FormatConfig{
|
||||
public RDFService.ModelSerializationFormat wireFormat;
|
||||
public String jenaResponseFormat;
|
||||
|
||||
public ModelFormatConfig( String valueFromForm,
|
||||
boolean converstionFromWireFormat,
|
||||
RDFService.ModelSerializationFormat wireFormat,
|
||||
String jenaResponseFormat,
|
||||
String responseMimeType){
|
||||
this.valueFromForm = valueFromForm;
|
||||
this.converstionFromWireFormat = converstionFromWireFormat;
|
||||
this.wireFormat = wireFormat;
|
||||
this.jenaResponseFormat = jenaResponseFormat;
|
||||
this.responseMimeType = responseMimeType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static RSFormatConfig[] rsfs = {
|
||||
new RSFormatConfig( "RS_XML",
|
||||
!CONVERT, ResultFormat.XML, null, "text/xml"),
|
||||
new RSFormatConfig( "RS_TEXT",
|
||||
!CONVERT, ResultFormat.TEXT, null, "text/plain"),
|
||||
new RSFormatConfig( "vitro:csv",
|
||||
!CONVERT, ResultFormat.CSV, null, "text/csv"),
|
||||
new RSFormatConfig( "RS_JSON",
|
||||
!CONVERT, ResultFormat.JSON, null, "application/javascript") };
|
||||
|
||||
public static class RSFormatConfig extends FormatConfig{
|
||||
public ResultFormat wireFormat;
|
||||
public ResultSetFormat jenaResponseFormat;
|
||||
|
||||
public RSFormatConfig( String valueFromForm,
|
||||
boolean converstionFromWireFormat,
|
||||
ResultFormat wireFormat,
|
||||
ResultSetFormat jenaResponseFormat,
|
||||
String responseMimeType ){
|
||||
this.valueFromForm = valueFromForm;
|
||||
this.converstionFromWireFormat = converstionFromWireFormat;
|
||||
this.wireFormat = wireFormat;
|
||||
this.jenaResponseFormat = jenaResponseFormat;
|
||||
this.responseMimeType = responseMimeType;
|
||||
}
|
||||
}
|
||||
|
||||
static{
|
||||
HashMap<String, Float> map = new HashMap<String, Float>();
|
||||
|
||||
/* move the lists of configurations into maps for easy lookup
|
||||
* by both MIME content type and the parameters from the form */
|
||||
for( RSFormatConfig rsfc : rsfs ){
|
||||
rsFormats.put( rsfc.valueFromForm, rsfc );
|
||||
rsFormats.put( rsfc.responseMimeType, rsfc);
|
||||
map.put(rsfc.responseMimeType, 1.0f);
|
||||
}
|
||||
for( ModelFormatConfig mfc : fmts ){
|
||||
modelFormats.put( mfc.valueFromForm, mfc);
|
||||
modelFormats.put(mfc.responseMimeType, mfc);
|
||||
map.put(mfc.responseMimeType, 1.0f);
|
||||
}
|
||||
|
||||
ACCEPTED_CONTENT_TYPES = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the content type based on content negotiation.
|
||||
* Returns null of no content type can be agreed on or
|
||||
* if there is no accept header.
|
||||
*/
|
||||
protected String checkForContentType( String acceptHeader ) {
|
||||
if (acceptHeader == null)
|
||||
return null;
|
||||
|
||||
try {
|
||||
Map<String, Float> typesAndQ = ContentType
|
||||
.getTypesAndQ(acceptHeader);
|
||||
|
||||
String ctStr = ContentType
|
||||
.getBestContentType(typesAndQ,ACCEPTED_CONTENT_TYPES);
|
||||
|
||||
if( ACCEPTED_CONTENT_TYPES.containsKey( ctStr )){
|
||||
return ctStr;
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
log.error("Problem while checking accept header ", th);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.admin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.query.Query;
|
||||
import com.hp.hpl.jena.query.QueryParseException;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Ontology;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.InvalidQueryTypeException;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.ResultSetMediaType;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.SparqlQueryApiExecutor;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.SparqlQueryUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.http.AcceptHeaderParsingException;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.http.NotAcceptableException;
|
||||
|
||||
/**
|
||||
* Present the SPARQL Query form, and execute the queries.
|
||||
*/
|
||||
public class SparqlQueryController extends FreemarkerHttpServlet {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(SparqlQueryController.class);
|
||||
|
||||
private static final String TEMPLATE_NAME = "admin-sparqlQueryForm.ftl";
|
||||
|
||||
/**
|
||||
* Always show these prefixes, even though they don't appear in the list of
|
||||
* ontologies.
|
||||
*/
|
||||
private static final List<Prefix> DEFAULT_PREFIXES = buildDefaults();
|
||||
|
||||
private static List<Prefix> buildDefaults() {
|
||||
Prefix[] array = new Prefix[] {
|
||||
new Prefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
|
||||
new Prefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#"),
|
||||
new Prefix("xsd", "http://www.w3.org/2001/XMLSchema#"),
|
||||
new Prefix("owl", "http://www.w3.org/2002/07/owl#"),
|
||||
new Prefix("swrl", "http://www.w3.org/2003/11/swrl#"),
|
||||
new Prefix("swrlb", "http://www.w3.org/2003/11/swrlb#"),
|
||||
new Prefix("vitro",
|
||||
"http://vitro.mannlib.cornell.edu/ns/vitro/0.7#") };
|
||||
return Collections.unmodifiableList(Arrays.asList(array));
|
||||
}
|
||||
|
||||
private static final String[] SAMPLE_QUERY = { //
|
||||
"", //
|
||||
"#", //
|
||||
"# This example query gets 20 geographic locations", //
|
||||
"# and (if available) their labels", //
|
||||
"#", //
|
||||
"SELECT ?geoLocation ?label", //
|
||||
"WHERE", //
|
||||
"{", //
|
||||
" ?geoLocation rdf:type vivo:GeographicLocation",
|
||||
" OPTIONAL { ?geoLocation rdfs:label ?label } ", //
|
||||
"}", //
|
||||
"LIMIT 20" //
|
||||
};
|
||||
|
||||
/**
|
||||
* If a query has been provided, we answer it directly, bypassing the
|
||||
* Freemarker mechanisms.
|
||||
*/
|
||||
@Override
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException, ServletException {
|
||||
if (!isAuthorizedToDisplayPage(req, resp,
|
||||
SimplePermission.USE_SPARQL_QUERY_PAGE.ACTIONS)) {
|
||||
return;
|
||||
}
|
||||
if (req.getParameterMap().containsKey("query")) {
|
||||
respondToQuery(req, resp);
|
||||
} else {
|
||||
super.doGet(req, resp);
|
||||
}
|
||||
}
|
||||
|
||||
private void respondToQuery(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
RDFService rdfService = RDFServiceUtils.getRDFServiceFactory(
|
||||
getServletContext()).getRDFService();
|
||||
|
||||
String queryString = req.getParameter("query");
|
||||
try {
|
||||
String format = interpretRequestedFormats(req, queryString);
|
||||
SparqlQueryApiExecutor core = SparqlQueryApiExecutor.instance(
|
||||
rdfService, queryString, format);
|
||||
resp.setContentType(core.getMediaType());
|
||||
core.executeAndFormat(resp.getOutputStream());
|
||||
} catch (InvalidQueryTypeException e) {
|
||||
do400BadRequest("Query type is not SELECT, ASK, CONSTRUCT, "
|
||||
+ "or DESCRIBE: '" + queryString + "'", resp);
|
||||
} catch (QueryParseException e) {
|
||||
do400BadRequest("Failed to parse query: '" + queryString + "''", e,
|
||||
resp);
|
||||
} catch (NotAcceptableException | AcceptHeaderParsingException e) {
|
||||
do500InternalServerError("Problem with the page fields: the "
|
||||
+ "selected fields do not include an "
|
||||
+ "acceptable content type.", e, resp);
|
||||
} catch (RDFServiceException e) {
|
||||
do500InternalServerError("Problem executing the query.", e, resp);
|
||||
}
|
||||
}
|
||||
|
||||
private String interpretRequestedFormats(HttpServletRequest req,
|
||||
String queryString) throws NotAcceptableException {
|
||||
Query query = SparqlQueryUtils.create(queryString);
|
||||
String parameterName = (query.isSelectType() || query.isAskType()) ? "resultFormat"
|
||||
: "rdfResultFormat";
|
||||
String parameterValue = req.getParameter(parameterName);
|
||||
if (StringUtils.isBlank(parameterValue)) {
|
||||
throw new NotAcceptableException("Parameter '" + parameterName
|
||||
+ "' was '" + parameterValue + "'.");
|
||||
} else {
|
||||
return parameterValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void do400BadRequest(String message, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(message);
|
||||
}
|
||||
|
||||
private void do400BadRequest(String message, Exception e,
|
||||
HttpServletResponse resp) throws IOException {
|
||||
resp.setStatus(400);
|
||||
PrintWriter w = resp.getWriter();
|
||||
w.println(message);
|
||||
e.printStackTrace(w);
|
||||
}
|
||||
|
||||
private void do500InternalServerError(String message, Exception e,
|
||||
HttpServletResponse resp) throws IOException {
|
||||
resp.setStatus(500);
|
||||
PrintWriter w = resp.getWriter();
|
||||
w.println(message);
|
||||
e.printStackTrace(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResponseValues processRequest(VitroRequest vreq) throws Exception {
|
||||
Map<String, Object> bodyMap = new HashMap<>();
|
||||
bodyMap.put("sampleQuery", buildSampleQuery(buildPrefixList(vreq)));
|
||||
bodyMap.put("title", "SPARQL Query");
|
||||
bodyMap.put("submitUrl", UrlBuilder.getUrl("admin/sparqlquery"));
|
||||
return new TemplateResponseValues(TEMPLATE_NAME, bodyMap);
|
||||
}
|
||||
|
||||
private List<Prefix> buildPrefixList(VitroRequest vreq) {
|
||||
List<Prefix> prefixList = new ArrayList<>(DEFAULT_PREFIXES);
|
||||
|
||||
OntologyDao dao = vreq.getUnfilteredWebappDaoFactory().getOntologyDao();
|
||||
List<Ontology> ontologies = dao.getAllOntologies();
|
||||
if (ontologies == null) {
|
||||
ontologies = Collections.emptyList();
|
||||
}
|
||||
|
||||
int unnamedOntologyIndex = 1;
|
||||
|
||||
for (Ontology ont : ontologies) {
|
||||
String prefix = ont.getPrefix();
|
||||
if (prefix == null) {
|
||||
prefix = "p" + unnamedOntologyIndex++;
|
||||
}
|
||||
prefixList.add(new Prefix(prefix, ont.getURI()));
|
||||
}
|
||||
|
||||
return prefixList;
|
||||
}
|
||||
|
||||
private String buildSampleQuery(List<Prefix> prefixList) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(sw);
|
||||
|
||||
for (Prefix p : prefixList) {
|
||||
writer.println(p);
|
||||
}
|
||||
for (String line : SAMPLE_QUERY) {
|
||||
writer.println(line);
|
||||
}
|
||||
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public static class Prefix {
|
||||
private final String prefix;
|
||||
private final String uri;
|
||||
|
||||
public Prefix(String prefix, String uri) {
|
||||
this.prefix = prefix;
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PREFIX %-9s <%s>", prefix + ":", uri);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue