From fd0240aa431974075a4053c763994310cebcb342 Mon Sep 17 00:00:00 2001 From: Jussi Koskela Date: Tue, 29 May 2018 10:29:45 +0300 Subject: [PATCH] Improvements to SCL HTTP client Add missing Proc effect to buildClient function. Function to read content length from response. Function to read headers from response. Option to add read / write progress callback functions. gitlab #11 Change-Id: Iaff99e05e35a494b154d7d5b04bd936bb95b0407 --- .../META-INF/MANIFEST.MF | 3 +- .../scl/HTTP/Client.scl | 8 ++- .../simantics/scl/rest/HttpClientUtils.java | 23 ++++++++ .../scl/rest/ReadProgressInterceptor.java | 55 +++++++++++++++++++ .../scl/rest/WriteProgressInterceptor.java | 47 ++++++++++++++++ 5 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/ReadProgressInterceptor.java create mode 100644 bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/WriteProgressInterceptor.java diff --git a/bundles/org.simantics.scl.rest/META-INF/MANIFEST.MF b/bundles/org.simantics.scl.rest/META-INF/MANIFEST.MF index 429a733d8..d013fba98 100644 --- a/bundles/org.simantics.scl.rest/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.scl.rest/META-INF/MANIFEST.MF @@ -23,6 +23,7 @@ Require-Bundle: org.eclipse.core.runtime, org.slf4j.api, org.jvnet.mimepull;bundle-version="1.9.6", org.glassfish.jersey.core.jersey-client, - org.glassfish.jersey.core.jersey-common;bundle-version="2.25.1" + org.glassfish.jersey.core.jersey-common;bundle-version="2.25.1", + org.simantics.scl.runtime Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy diff --git a/bundles/org.simantics.scl.rest/scl/HTTP/Client.scl b/bundles/org.simantics.scl.rest/scl/HTTP/Client.scl index 9ebeeea8f..6568116c9 100644 --- a/bundles/org.simantics.scl.rest/scl/HTTP/Client.scl +++ b/bundles/org.simantics.scl.rest/scl/HTTP/Client.scl @@ -24,6 +24,8 @@ importJava "javax.ws.rs.core.Response" where @Private @JavaName readEntity readEntity_ :: Response -> Class a -> a + @JavaName getHeaderString + possibleHeaderOf :: Response -> String -> Maybe String readEntity :: VecComp a => Response -> a readEntity response = readEntity_ response classObject @@ -73,10 +75,13 @@ importJava "javax.ws.rs.client.ClientBuilder" where clientBuilder :: ClientBuilder importJava "org.simantics.scl.rest.HttpClientUtils" where - buildClient :: ClientBuilder -> Client + buildClient :: ClientBuilder -> Client statusMessageOf :: Response -> String asyncInvoke :: Invocation -> ResponseHandler -> FailureHandler -> Future Response trustAllClientBuilder :: ClientBuilder + onReadProgress :: WebTarget -> (Long -> ()) -> () + onWriteProgress :: WebTarget -> (Long -> ()) -> () + possibleContentLengthOf :: Response -> Maybe Long importJava "javax.ws.rs.client.Entity" where data Entity @@ -133,7 +138,6 @@ postFileExample uri f = do webTarget = target httpClient uri builder = request webTarget acceptMediaType builder [WILDCARD_TYPE] - mp = formDataMultiPart invocation = buildPost builder $ entity f APPLICATION_OCTET_STREAM_TYPE response = syncInvoke invocation print $ statusCodeOf response diff --git a/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/HttpClientUtils.java b/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/HttpClientUtils.java index ef42cc859..f99b8c47f 100644 --- a/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/HttpClientUtils.java +++ b/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/HttpClientUtils.java @@ -14,6 +14,7 @@ import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.InvocationCallback; +import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Configuration; import javax.ws.rs.core.Response; @@ -85,4 +86,26 @@ public class HttpClientUtils { } }); } + + public static void onWriteProgress(WebTarget target, Function1 callback) { + target.register(new WriteProgressInterceptor(callback)); + } + + public static void onReadProgress(WebTarget target, Function1 callback) { + target.register(new ReadProgressInterceptor(callback)); + } + + public static Long possibleContentLengthOf(Response response) { + String lengthStr = response.getHeaderString("Content-Length"); + if (lengthStr != null) { + try { + return Long.parseLong(lengthStr); + } catch (NumberFormatException e) { + return null; + } + } else { + return null; + } + } + } diff --git a/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/ReadProgressInterceptor.java b/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/ReadProgressInterceptor.java new file mode 100644 index 000000000..6b3d72ffc --- /dev/null +++ b/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/ReadProgressInterceptor.java @@ -0,0 +1,55 @@ +package org.simantics.scl.rest; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.ReaderInterceptorContext; + +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.tuple.Tuple0; + +public class ReadProgressInterceptor implements ReaderInterceptor { + + private Function1 callback; + + public ReadProgressInterceptor(Function1 callback) { + this.callback = callback; + } + + @Override + public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException { + + final InputStream is = context.getInputStream(); + + context.setInputStream(new FilterInputStream(is) { + + private long count; + + @Override + public int read(byte b[], int off, int len) throws IOException { + int read = in.read(b, off, len); + if (read > 0) { + count += read; + callback.apply(count); + } + return read; + } + + @Override + public int read() throws IOException { + int read = in.read(); + if (read > 0) { + count++; + callback.apply(count); + } + return read; + } + }); + + return context.proceed(); + } + +} diff --git a/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/WriteProgressInterceptor.java b/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/WriteProgressInterceptor.java new file mode 100644 index 000000000..ebbc85f05 --- /dev/null +++ b/bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/WriteProgressInterceptor.java @@ -0,0 +1,47 @@ +package org.simantics.scl.rest; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.ext.WriterInterceptor; +import javax.ws.rs.ext.WriterInterceptorContext; + +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.tuple.Tuple0; + +public class WriteProgressInterceptor implements WriterInterceptor { + + private Function1 callback; + + public WriteProgressInterceptor(Function1 callback) { + this.callback = callback; + } + + @Override + public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { + + final OutputStream os = context.getOutputStream(); + + context.setOutputStream(new FilterOutputStream(os) { + private long count; + + @Override public void write(byte[] b, int off, int len) throws IOException { + out.write(b, off, len); + count += len; + callback.apply(count); + } + + @Override + public void write(int b) throws IOException { + out.write(b); + count++; + callback.apply(count); + } + }); + + context.proceed(); + } + +} -- 2.43.2