Separate export method from response method and adopt progress calculation for sse
Change-Id: I0d2e6d206a1b19475905528c2f8400dd25c418d7
diff --git a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Exporter.java b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Exporter.java
index 72e4b0e..ca11226 100644
--- a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Exporter.java
+++ b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Exporter.java
@@ -5,6 +5,10 @@
import java.io.IOException;
import java.io.Writer;
+import javax.ws.rs.sse.Sse;
+import javax.ws.rs.sse.SseEventSink;
+
+
interface Exporter {
// Implemented by MatchAggregator
@@ -24,10 +28,10 @@
public void setCorpusQueryString (String s);
public String getSource ();
public void setSource (String h, String p);
-
public int getTotalResults ();
public boolean hasTimeExceeded ();
public void setMaxResults (int m);
+ public void setSse (SseEventSink sink, Sse sse);
// Implemented by Exporter
public ResponseBuilder serve();
diff --git a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/MatchAggregator.java b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/MatchAggregator.java
index 41b7b47..c29a7c2 100644
--- a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/MatchAggregator.java
+++ b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/MatchAggregator.java
@@ -158,15 +158,11 @@
// Send the progress
private void sendProgress () {
- if (this.sink == null)
+ if (this.sink == null || this.maxResults == 0)
return;
- double calc = Math.ceil(
- (
- (float) this.fetchedResults / (float) this.maxResults
- ) * 100
- );
- this.sink.send(this.sse.newEvent("progress", String.valueOf(calc)));
+ int calc = (int) Math.ceil(((double) this.fetchedResults / this.maxResults) * 100);
+ this.sink.send(this.sse.newEvent("Progress", String.valueOf(calc)));
};
/**
diff --git a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Service.java b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Service.java
index e65572c..eb644b1 100644
--- a/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Service.java
+++ b/plugin/src/main/java/de/ids_mannheim/korap/plkexport/Service.java
@@ -22,6 +22,7 @@
import javax.ws.rs.BadRequestException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.FormParam;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.POST;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -89,40 +90,17 @@
@Context
private HttpServletRequest req;
- /**
- * WebService calls Kustvakt Search Webservices and returns
- * response as json (all of the response) and
- * as rtf (matches)
- *
- * @param fname
- * file name
- * @param format
- * the file format value rtf or json.
- * @param q
- * the query
- * @param ql
- * the query language
- * @param cutoff
- * Export more than the first page
- *
- *
- */
- @POST
- @Path("export")
- @Produces(MediaType.APPLICATION_OCTET_STREAM)
- public Response staticExport (
- @FormParam("fname") String fname,
- @FormParam("format") String format,
- @FormParam("q") String q,
- @FormParam("cq") String cq,
- @FormParam("ql") String ql,
- @FormParam("cutoff") String cutoffStr,
- @FormParam("hitc") int hitc
- // @FormParam("islimit") String il
- ) throws IOException {
-
- // Exporter exp =
- // return progressExport(fname, format, q, cq, ql, cutoffStr, hitc, null, null);
+ // Private method to run the export,
+ // either static or streaming
+ private Exporter export (String fname,
+ String format,
+ String q,
+ String cq,
+ String ql,
+ String cutoffStr,
+ int hitc,
+ SseEventSink sink,
+ Sse sse) throws WebApplicationException {
// These parameters are required
String[][] params = {
@@ -134,12 +112,11 @@
// Check that all parameters are available
for (int i = 0; i < params.length; i++) {
if (params[i][1] == null || params[i][1].trim().isEmpty())
- throw new BadRequestException(
- Response
- .status(Status.BAD_REQUEST)
- .entity("Parameter " + "\""
- + params[i][0] + "\"" + " is missing or empty")
- .build());
+ throw new WebApplicationException(
+ responseForm(Status.BAD_REQUEST,
+ "Parameter " + "\""
+ + params[i][0] + "\"" +
+ " is missing or empty"));
};
// Retrieve cutoff value
@@ -151,9 +128,6 @@
cutoff = true;
};
- ResponseBuilder builder = null;
- Client client = ClientBuilder.newClient();
-
// Load configuration values
String scheme = prop.getProperty("api.scheme", "https");
String port = prop.getProperty("api.port", "8089");
@@ -169,7 +143,10 @@
// If less than pageSize results are requested - dont't fetch more
if (maxResults < pageSize)
pageSize = maxResults;
-
+
+ ResponseBuilder builder = null;
+ Client client = ClientBuilder.newClient();
+
// Create initial search uri
UriBuilder uri = UriBuilder.fromPath("/api/v1.0/search")
.host(host)
@@ -236,10 +213,15 @@
exp.setFileName(fname);
};
- // if (sse != null && sink != null) {
- // exp.setSSE(sse, sink);
- // };
+ // set progress mechanism, if required
+ if (sse != null && sink != null)
+ exp.setSse(sink, sse);
+ // TODO:
+ // The following could be subsumed in the MatchAggregator
+ // as a "run()" routine.
+
+
// Initialize exporter (with meta data and first matches)
try {
exp.init(resp);
@@ -258,12 +240,10 @@
int fetchCount = exp.getTotalResults();
if (exp.hasTimeExceeded() || fetchCount > maxResults) {
fetchCount = maxResults;
- };
- // TODO:
- // else {
- // setMaxResults()???
- // }
+ }
+ // fetchCount may be different to maxResults now, so reset after init
+ exp.setMaxResults(fetchCount);
// The first page was already enough - ignore paging
if (fetchCount <= pageSize) {
@@ -273,10 +253,7 @@
// If only one page should be exported there is no need
// for a temporary export file
if (cutoff) {
-
- // TODO:
- // Add method serveAndBuild()
- return exp.serve().build();
+ return exp;
};
// Page through all results
@@ -307,34 +284,96 @@
)
);
};
+
+ return exp;
+ };
+
+
+ /**
+ * WebService calls Kustvakt Search Webservices and returns
+ * response as json (all of the response) and
+ * as rtf (matches)
+ *
+ * @param fname
+ * file name
+ * @param format
+ * the file format value rtf or json.
+ * @param q
+ * the query
+ * @param ql
+ * the query language
+ * @param cutoff
+ * Export more than the first page
+ *
+ *
+ */
+ @POST
+ @Path("export")
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ public Response staticExport (
+ @FormParam("fname") String fname,
+ @FormParam("format") String format,
+ @FormParam("q") String q,
+ @FormParam("cq") String cq,
+ @FormParam("ql") String ql,
+ @FormParam("cutoff") String cutoffStr,
+ @FormParam("hitc") int hitc
+ // @FormParam("islimit") String il
+ ) throws IOException {
+
+ Exporter exp = export(fname, format, q, cq, ql, cutoffStr, hitc, null, null);
return exp.serve().build();
};
+
-
+ /**
+ * Progress based counterpart to staticExport,
+ * that requires a GET due to the JavaScript API.
+ */
@GET
@Path("export")
@Produces("text/event-stream")
- public void progressExport(@Context SseEventSink sseEventSink,
- @Context Sse sse) throws InterruptedException {
-
- // Exporter exp =
- // progressExport(fname, format, q, cq, ql, cutoffStr, hitc, null, null);
+ public void progressExport(
+ @Context SseEventSink sink,
+ @Context Sse sse,
+ @QueryParam("fname") String fname,
+ @QueryParam("format") String format,
+ @QueryParam("q") String q,
+ @QueryParam("cq") String cq,
+ @QueryParam("ql") String ql,
+ @QueryParam("cutoff") String cutoffStr,
+ @QueryParam("hitc") int hitc
+ ) throws InterruptedException {
// https://www.baeldung.com/java-ee-jax-rs-sse
// https://www.howopensource.com/2016/01/java-sse-chat-example/
// https://csetutorials.com/jersey-sse-tutorial.html
- sseEventSink.send(sse.newEvent("Init", "Start"));
- int x = 0;
- while (x < 100) {
- x++;
- sseEventSink.send(sse.newEvent("Progress", ""+x));
+ // Send initial event
+ sink.send(sse.newEvent("Process", "Init"));
+
+ try {
+ Exporter exp = export(
+ fname,
+ format,
+ q,
+ cq,
+ ql,
+ cutoffStr,
+ hitc,
+ sink,
+ sse
+ );
+ sink.send(sse.newEvent("Relocate", "..."));
+ }
+ catch (WebApplicationException wae) {
+ sink.send(sse.newEvent("Error",wae.getMessage()));
};
- sseEventSink.send(sse.newEvent("Relocate", "location"));
-
- sseEventSink.close();
+ sink.send(sse.newEvent("Process", "Done"));
+
+ sink.close();
};