VIVO-734 implement listrdf by delegating to SparqlQueryApiExecutor.
It formerly retrieved the data from Solr.
This commit is contained in:
parent
6178aa0347
commit
10d692d411
4 changed files with 139 additions and 74 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue