package eu.geoknow.generator.rest;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.ws.rs.CookieParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.ws.http.HTTPException;
import org.apache.log4j.Logger;
import eu.geoknow.generator.configuration.FrameworkConfiguration;
import eu.geoknow.generator.exceptions.NotAuthorizedException;
import eu.geoknow.generator.exceptions.UnsupportedAuthenticationType;
import eu.geoknow.generator.rdf.RdfStoreManager;
import eu.geoknow.generator.users.FrameworkUserManager;
import eu.geoknow.generator.users.UserProfile;
/**
* This servlet redirects SPARQL query to RDF store without any changes and returns original SPARQL
* result in response. It can communicate both with public and secure SPARQL endpoints (user name
* required).
*/
@Path("/RdfStoreProxy")
public class RdfStoreProxy {
private static final Logger log = Logger.getLogger(RdfStoreProxy.class);
/**
* Send SPARQL request to RDF store and return original result.
*
* @param context servlet context
* @param token user token specified in cookies
* @param username user name for secure SPARQL endpoint
* @param query SPARQL query
* @param mode if this parameter is set to "settings" SPARQL query will be executed with framework
* admin credentials
* @param responseFormat SPARQL response format
* @return
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response executeQuery(@Context ServletContext context, @CookieParam("token") String token,
@FormParam("username") String username, @FormParam("query") String query,
@FormParam("mode") String mode, @FormParam("format") String responseFormat) {
FrameworkConfiguration frameworkConfiguration;
try {
frameworkConfiguration = FrameworkConfiguration.getInstance();
FrameworkUserManager frameworkUserManager = frameworkConfiguration.getFrameworkUserManager();
RdfStoreManager frameworkRdfStoreManager = frameworkConfiguration.getSystemRdfStoreManager();
log.debug("mode: " + mode);
log.debug("username: " + username);
RdfStoreManager rdfStoreManager;
if ("settings".equals(mode)) {
// read user settings graph - use framework admin user for that
// purpose
// here we need to check if system is set up, if not we cannot
// query settings - framework admin user and settings graph
// don't exist
if (!frameworkConfiguration.isSetUp()) {
log.info("System is not set up");
// if Workbench is not set up return empty SPARQL result
// like if no settings were found
// in this case we don't get any parsing or http fail errors
// in frontend
// maybe it is better to return error response, but in this
// case we have to change some frontend code to distinguish
// between real SPARQL errors and this special case
String emptySPARQLResponse =
"{ \"head\": { \"link\": [], \"vars\": [\"s\", \"p\", \"o\"] }, \"results\": { \"distinct\": false, \"ordered\": false, \"bindings\": [] }}";
return Response.status(Response.Status.OK).entity(emptySPARQLResponse).build();
} else {
log.info("Use admin rdf store manager");
rdfStoreManager = frameworkRdfStoreManager;
}
} else if (username != null && !username.isEmpty()) { // execute
// query using
// given user
// credentials
boolean valid = frameworkUserManager.checkToken(username, token);
if (!valid)
return Response.status(Response.Status.FORBIDDEN).entity("User token is invalid").build();
log.info("Use user rdf manager");
rdfStoreManager = frameworkUserManager.getRdfStoreManager(username);
} else { // no username provided => use public endpoint
log.info("Use public rdf manager");
rdfStoreManager = frameworkConfiguration.getPublicRdfStoreManager();
}
String result = rdfStoreManager.execute(query, responseFormat);
return Response.status(Response.Status.OK).entity(result).build();
} catch (HTTPException e) {
log.error("Failed to execute SPARQL query", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
} catch (UnsupportedAuthenticationType e) {
log.error("Failed to authenticate", e);
return Response.status(Response.Status.EXPECTATION_FAILED).entity(e.getMessage()).build();
} catch (IOException e) {
log.error("Failed to authenticate", e);
return Response.status(Response.Status.EXPECTATION_FAILED).entity(e.getMessage()).build();
} catch (NotAuthorizedException e) {
log.error("Failed to get settings", e);
return e.getResponse();
} catch (Exception e) {
log.error("Failed to get settings", e);
return Response.status(Response.Status.EXPECTATION_FAILED).entity(e.getMessage()).build();
}
}
@POST
@Path("/rewriteGraph")
@Produces(MediaType.APPLICATION_JSON)
public Response rewriteGraph(@Context ServletContext context, @CookieParam("token") String token,
@CookieParam(value = "user") Cookie userc, @FormParam("graph") String graph,
@FormParam("data") String data, @FormParam("prefixes") String prefixes,
@FormParam("mode") String mode, @FormParam("format") String responseFormat) {
try {
FrameworkConfiguration frameworkConfiguration = FrameworkConfiguration.getInstance();
FrameworkUserManager frameworkUserManager = frameworkConfiguration.getFrameworkUserManager();
RdfStoreManager frameworkRdfStoreManager = frameworkConfiguration.getSystemRdfStoreManager();
RdfStoreManager rdfStoreManager;
UserProfile user =
FrameworkConfiguration.getInstance().getFrameworkUserManager().validate(userc, token);
if ("settings".equals(mode)) { // rewrite user settings graph - use
// framework admin user for that
// purpose
// here we need to check if system is set up, if not we cannot
// rewrite settings - framework admin user and settings graph
// don't exist
if (!frameworkConfiguration.isSetUp()) {
log.error("System is not set up");
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Failed to rewrite graph " + graph + ": system is not set up").build();
} else {
log.info("Use admin rdf store manager");
rdfStoreManager = frameworkRdfStoreManager;
}
} else if (user != null) { // execute query using given user
// credentials
rdfStoreManager = frameworkUserManager.getRdfStoreManager(user.getUsername());
} else { // no username provided => use public endpoint
log.info("Use public rdf manager");
rdfStoreManager = frameworkConfiguration.getPublicRdfStoreManager();
}
// OntoQuad doesn't support DROP and CREATE operations, so we need
// to execute it via RdfStoreManager (cannot send everything in one
// query)
// todo optimisation for Virtuoso is possible: send DROP, CREATE and
// INSERT DATA in one query
rdfStoreManager.dropGraph(graph);
rdfStoreManager.createGraph(graph);
String query = "";
query = (prefixes == null ? "" : prefixes) + " INSERT INTO <" + graph + "> { " + data + " } ";
String result = rdfStoreManager.execute(query, responseFormat);
return Response.status(Response.Status.OK).entity(result).build();
} catch (Exception e) {
log.error("Failed to execute SPARQL query", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
}
}