package org.aksw.jena_sparql_api.web.servlets; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.CompletionCallback; import javax.ws.rs.container.ConnectionCallback; import javax.ws.rs.container.Suspended; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.StreamingOutput; import org.aksw.jena_sparql_api.core.SparqlService; import org.aksw.jena_sparql_api.core.SparqlServiceFactory; import org.aksw.jena_sparql_api.core.UpdateExecutionFactory; import org.aksw.jena_sparql_api.core.utils.UpdateRequestUtils; import org.aksw.jena_sparql_api.web.utils.AuthenticatorUtils; import org.aksw.jena_sparql_api.web.utils.ThreadUtils; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.HttpClient; import org.apache.jena.sparql.core.DatasetDescription; import org.apache.jena.update.UpdateProcessor; import org.apache.jena.update.UpdateRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class ServletSparqlUpdateBase { private static final Logger logger = LoggerFactory.getLogger(ServletSparqlUpdateBase.class); protected @Context HttpServletRequest req; protected abstract SparqlServiceFactory getSparqlServiceFactory(); @GET @Produces(MediaType.APPLICATION_JSON) public void executeUpdateGet(@Suspended final AsyncResponse asyncResponse, @QueryParam("service-uri") String serviceUri, @QueryParam("update") String queryString, @QueryParam("using-graph-uri") List<String> usingGraphUris, @QueryParam("using-named-graph-uri") List<String> usingNamedGraphUris) throws Exception { executeUpdateAny(asyncResponse, serviceUri, queryString, usingGraphUris, usingNamedGraphUris); } @POST @Produces(MediaType.APPLICATION_JSON) public void executeUpdatePost(@Suspended final AsyncResponse asyncResponse, @FormParam("service-uri") String serviceUri, @FormParam("update") String queryString, @FormParam("using-graph-uri") List<String> usingGraphUris, @FormParam("using-named-graph-uri") List<String> usingNamedGraphUris) throws Exception { executeUpdateAny(asyncResponse, serviceUri, queryString, usingGraphUris, usingNamedGraphUris); } public void executeUpdateAny(@Suspended final AsyncResponse asyncResponse, String serviceUri, String queryString, List<String> usingGraphUris, List<String> usingNamedGraphUris) throws Exception { if(queryString == null) { StreamingOutput so = StreamingOutputString.create("<error>No query specified. Append '?query=<your SPARQL query>'</error>"); asyncResponse.resume(Response.status(Status.BAD_REQUEST).entity(so).build()); // TODO: Return some error HTTP code } else { processUpdateAsync(asyncResponse, serviceUri, queryString, usingGraphUris, usingNamedGraphUris); } } public UpdateProcessor createUpdateProcessor(String serviceUri, String requestStr, List<String> usingGraphUris, List<String> usingNamedGraphUris) { UsernamePasswordCredentials credentials = AuthenticatorUtils.parseCredentials(req); HttpClient httpClient = AuthenticatorUtils.prepareHttpClientBuilder(credentials).build(); SparqlServiceFactory ssf = getSparqlServiceFactory(); UpdateProcessor result = createUpdateProcessor(ssf, serviceUri, requestStr, usingGraphUris, usingNamedGraphUris, httpClient); return result; } public static UpdateProcessor createUpdateProcessor(SparqlServiceFactory ssf, String serviceUri, String requestStr, List<String> usingGraphUris, List<String> usingNamedGraphUris, HttpClient httpClient) { // TODO Should we use UsingList or DatasetDescription? The latter feels more natural to use. // UsingList usingList = new UsingList(); // usingList.addAllUsing(NodeUtils.convertToNodes(usingGraphUris)); // usingList.addAllUsingNamed(NodeUtils.convertToNodes(usingNamedGraphUris)); DatasetDescription datasetDescription = new DatasetDescription(usingGraphUris, usingNamedGraphUris); SparqlService sparqlService = ssf.createSparqlService(serviceUri, datasetDescription, httpClient); UpdateExecutionFactory uef = sparqlService.getUpdateExecutionFactory(); UpdateRequest updateRequest = UpdateRequestUtils.parse(requestStr); UpdateProcessor result = uef.createUpdateProcessor(updateRequest); return result; } public void processUpdateAsync(final AsyncResponse response, String serviceUri, String requestStr, List<String> usingGraphUris, List<String> usingNamedGraphUris) { UpdateProcessor updateProcessor = createUpdateProcessor(serviceUri, requestStr, usingGraphUris, usingNamedGraphUris); updateProcessor.execute(); // QueryExecutionAndType tmp; // // try { // tmp = createQueryExecution(queryString); // } catch(Exception e) { // //// response.resume( //// Response.status(Response.Status.SERVICE_UNAVAILABLE) //// .entity("Connection Callback").build()); //// //// return; // throw new RuntimeException(e); // } // final QueryExecutionAndType qeAndType = tmp; // asyncResponse // .register(new CompletionCallback() { // // @Override // public void onComplete(Throwable arg0) { // System.out.println("COMPLETE"); // } // }); response .register(new ConnectionCallback() { @Override public void onDisconnect(AsyncResponse disconnect) { logger.debug("Client disconnected"); // TODO Abort //qeAndType.getQueryExecution().abort(); // if(true) { // disconnect.resume( // Response.status(Response.Status.SERVICE_UNAVAILABLE) // .entity("Connection Callback").build()); // } else { // disconnect.cancel(); // } } }); response .register(new CompletionCallback() { @Override public void onComplete(Throwable t) { if(t == null) { logger.debug("Successfully completed query execution"); } else { logger.debug("Failed query execution"); } //qeAndType.getQueryExecution().close(); // TODO Close } }); // response // .setTimeoutHandler(new TimeoutHandler() { // @Override // public void handleTimeout(AsyncResponse asyncResponse) { // logger.debug("Timout on request"); // asyncResponse.resume( // Response.status(Response.Status.SERVICE_UNAVAILABLE) // .entity("Operation time out.").build()); // } // }); // // response.setTimeout(600, TimeUnit.SECONDS); ThreadUtils.start(response, new Runnable() { @Override public void run() { try { String result = "{\"success\": true}"; //StreamingOutput result = ProcessQuery.processQuery(qeAndType, format); response.resume(result); } catch(Exception e) { throw new RuntimeException(e); } } }); } }