VIVO-734 implement listrdf by delegating to SparqlQueryApiExecutor.

It formerly retrieved the data from Solr.
This commit is contained in:
Jim Blake 2014-05-06 15:09:27 -04:00
parent 6178aa0347
commit 10d692d411
4 changed files with 139 additions and 74 deletions

View file

@ -1,6 +1,14 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller;
import static edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.RdfResultMediaType.RDF_XML;
import static edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary.RDF_TYPE;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_NOT_ACCEPTABLE;
import java.io.IOException;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -9,76 +17,118 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.query.QueryParseException;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.vocabulary.RDF;
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchQuery;
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResponse;
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocument;
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocumentList;
import edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames;
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.publish.PublishObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.controller.api.VitroApiServlet;
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.InvalidQueryTypeException;
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.RdfResultMediaType;
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.SparqlQueryApiExecutor;
import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess;
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.http.AcceptHeaderParsingException;
import edu.cornell.mannlib.vitro.webapp.utils.http.NotAcceptableException;
public class IndividualListRdfController extends VitroHttpServlet {
public class IndividualListRdfController extends VitroApiServlet {
private static final Log log = LogFactory
.getLog(IndividualListRdfController.class);
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(IndividualListRdfController.class.getName());
public static final int ENTITY_LIST_CONTROLLER_MAX_RESULTS = 30000;
@Override
public void doGet (HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
SearchEngine search = ApplicationUtils.instance().getSearchEngine();
// Make the query
String vclassUri = req.getParameter("vclass");
String queryStr = VitroSearchTermNames.RDFTYPE + ":\"" + vclassUri + "\"";
SearchQuery query = search.createQuery(queryStr);
query.setStart(0)
.setRows(ENTITY_LIST_CONTROLLER_MAX_RESULTS)
.addFields(VitroSearchTermNames.URI);
// For now, we're only displaying the url, so no need to sort.
//.addSortField(VitroSearchTermNames.NAME_LOWERCASE_SINGLE_VALUED);
private static final String QUERY_TEMPLATE = "CONSTRUCT { ?s a ?vclass . } WHERE { ?s a ?vclass . }";
// Execute the query
SearchResponse response = null;
try {
response = search.query(query);
} catch (Throwable t) {
log.error(t, t);
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
try {
String vclassUri = getVClassParameter(req);
RdfResultMediaType mediaType = parseAcceptHeader(req);
log.debug("Requested class is '" + vclassUri + "', media type is "
+ mediaType);
if ( response == null ) {
throw new ServletException("Could not run search in IndividualListRdfController");
}
if (isVclassRestricted(vclassUri, req)) {
sendEmptyModel(mediaType, resp);
} else {
executeQuery(buildQuery(vclassUri), mediaType.getContentType(),
getRdfService(req), resp);
}
} catch (BadParameterException e) {
sendShortResponse(SC_BAD_REQUEST, e.getMessage(), resp);
} catch (NotAcceptableException | AcceptHeaderParsingException e) {
sendShortResponse(SC_NOT_ACCEPTABLE,
"The accept header does not include any "
+ "available content type.", e, resp);
} catch (Exception e) {
sendShortResponse(SC_INTERNAL_SERVER_ERROR,
"Failed to obtain the list.", e, resp);
}
}
SearchResultDocumentList docs = response.getResults();
if (docs == null) {
throw new ServletException("Could not run search in IndividualListRdfController");
}
private String getVClassParameter(HttpServletRequest req)
throws BadParameterException {
String vclass = req.getParameter("vclass");
if (vclass == null) {
throw new BadParameterException(
"vclass parameter was not supplied.");
}
if (vclass.trim().isEmpty()) {
throw new BadParameterException("vclass parameter is empty.");
}
return vclass;
}
Model model = ModelFactory.createDefaultModel();
for (SearchResultDocument doc : docs) {
String uri = doc.getStringValue(VitroSearchTermNames.URI);
Resource resource = ResourceFactory.createResource(uri);
RDFNode node = ResourceFactory.createResource(vclassUri);
model.add(resource, RDF.type, node);
}
private RdfResultMediaType parseAcceptHeader(HttpServletRequest req)
throws NotAcceptableException, AcceptHeaderParsingException {
String defaultType = RDF_XML.getContentType();
Collection<String> availableTypes = RdfResultMediaType.contentTypes();
String contentType = parseAcceptHeader(req, availableTypes, defaultType);
return RdfResultMediaType.fromContentType(contentType);
}
private boolean isVclassRestricted(String vclassUri, HttpServletRequest req) {
ObjectProperty property = new ObjectProperty();
property.setURI(RDF_TYPE);
RequestedAction dops = new PublishObjectPropertyStatement(ModelAccess
.on(req).getBaseOntModel(), RequestedAction.SOME_URI, property,
vclassUri);
return !PolicyHelper.isAuthorizedForActions(req, dops);
}
private void sendEmptyModel(RdfResultMediaType mediaType,
HttpServletResponse resp) throws IOException {
resp.setContentType(mediaType.getContentType());
Model m = ModelFactory.createDefaultModel();
m.write(resp.getOutputStream(), mediaType.getJenaResponseFormat());
}
private String buildQuery(String vclassUri) {
return QUERY_TEMPLATE.replace("?vclass", "<" + vclassUri + ">");
}
private RDFService getRdfService(HttpServletRequest req) {
return RDFServiceUtils.getRDFService(new VitroRequest(req));
}
private void executeQuery(String query, String contentType,
RDFService rdfService, HttpServletResponse resp)
throws QueryParseException, NotAcceptableException,
InvalidQueryTypeException, AcceptHeaderParsingException,
RDFServiceException, IOException {
SparqlQueryApiExecutor executor = SparqlQueryApiExecutor.instance(
rdfService, query, contentType);
resp.setContentType(executor.getMediaType());
executor.executeAndFormat(resp.getOutputStream());
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
doGet(req, res);
}
res.setContentType(RDFXML_MIMETYPE);
model.write(res.getOutputStream(), "RDF/XML");
}
@Override
public void doPost (HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException{
doGet(req,res);
}
}

View file

@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.controller.api;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@ -16,6 +17,9 @@ import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
import edu.cornell.mannlib.vitro.webapp.utils.http.AcceptHeaderParsingException;
import edu.cornell.mannlib.vitro.webapp.utils.http.ContentTypeUtil;
import edu.cornell.mannlib.vitro.webapp.utils.http.NotAcceptableException;
/**
* The base class for Vitro servlets that implement the API.
@ -56,6 +60,17 @@ public class VitroApiServlet extends HttpServlet {
log.debug("Authorized for '" + email + "'");
}
protected String parseAcceptHeader(HttpServletRequest req,
Collection<String> availableTypes, String defaultType)
throws AcceptHeaderParsingException, NotAcceptableException {
String acceptHeader = req.getHeader("Accept");
if (acceptHeader == null) {
return defaultType;
}
acceptHeader += "," + defaultType + ";q=0.1";
return ContentTypeUtil.bestContentType(acceptHeader, availableTypes);
}
protected void sendShortResponse(int statusCode, String message,
HttpServletResponse resp) throws IOException {
resp.setStatus(statusCode);
@ -63,8 +78,8 @@ public class VitroApiServlet extends HttpServlet {
writer.println("<H1>" + statusCode + " " + message + "</H1>");
}
protected void sendShortResponse(int statusCode, String message, Throwable e,
HttpServletResponse resp) throws IOException {
protected void sendShortResponse(int statusCode, String message,
Throwable e, HttpServletResponse resp) throws IOException {
sendShortResponse(statusCode, message, resp);
PrintWriter writer = resp.getWriter();
writer.println("<pre>");
@ -77,15 +92,15 @@ public class VitroApiServlet extends HttpServlet {
// ----------------------------------------------------------------------
protected static class AuthException extends Exception {
protected AuthException(String message) {
public AuthException(String message) {
super(message);
}
}
protected static class BadParameterException extends Exception {
protected BadParameterException(String message) {
public BadParameterException(String message) {
super(message);
}
}
}

View file

@ -12,11 +12,11 @@ import java.util.Map;
* and DESCRIBE).
*/
public enum RdfResultMediaType {
TEXT("text/plain", true, "NTRIPLE", null),
TEXT("text/plain", true, "NTRIPLE", "N-TRIPLE"),
RDF_XML("application/rdf+xml", true, "RDFXML", null),
RDF_XML("application/rdf+xml", true, "RDFXML", "RDF/XML"),
N3("text/n3", true, "N3", null),
N3("text/n3", true, "N3", "N3"),
TTL("text/turtle", false, "N3", "TTL"),
@ -73,8 +73,7 @@ public enum RdfResultMediaType {
private final String serializationFormat;
/**
* What format shall we ask the resulting OntModel to write? (Applies only
* to non-native formats)
* What format shall we ask the resulting OntModel to write?
*/
private final String jenaResponseFormat;

View file

@ -62,8 +62,9 @@ public class ContentTypeUtil {
if (bestMatch == null) {
throw new NotAcceptableException(
"No available type matches the Accept header: "
+ acceptHeader);
"No available type matches the Accept header: '"
+ acceptHeader + "'; available types are "
+ availableTypeNames);
} else {
return bestMatch.getName();
}