Improvements to SCL HTTP client 08/1808/1
authorJussi Koskela <jussi.koskela@semantum.fi>
Tue, 29 May 2018 07:29:45 +0000 (10:29 +0300)
committerJussi Koskela <jussi.koskela@semantum.fi>
Tue, 29 May 2018 07:29:45 +0000 (10:29 +0300)
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

bundles/org.simantics.scl.rest/META-INF/MANIFEST.MF
bundles/org.simantics.scl.rest/scl/HTTP/Client.scl
bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/HttpClientUtils.java
bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/ReadProgressInterceptor.java [new file with mode: 0644]
bundles/org.simantics.scl.rest/src/org/simantics/scl/rest/WriteProgressInterceptor.java [new file with mode: 0644]

index 429a733d8fc8ecca77099509900bc3b0e772a1d8..d013fba98f194a25f41920bab87ec4cecd6d9661 100644 (file)
@@ -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
index 9ebeeea8f8907994ed5430d1a4ce1adc0f89afff..6568116c9e6a5d9c496e45e16b9b06e5075b1bde 100644 (file)
@@ -24,6 +24,8 @@ importJava "javax.ws.rs.core.Response" where
     @Private
     @JavaName readEntity
     readEntity_ :: Response -> Class a -> <Proc, Exception> a
+    @JavaName getHeaderString
+    possibleHeaderOf :: Response -> String -> <Proc> Maybe String
 
 readEntity :: VecComp a => Response -> <Proc, Exception> a
 readEntity response = readEntity_ response classObject
@@ -73,10 +75,13 @@ importJava "javax.ws.rs.client.ClientBuilder" where
     clientBuilder :: <Proc> ClientBuilder
 
 importJava "org.simantics.scl.rest.HttpClientUtils" where
-    buildClient :: ClientBuilder -> Client
+    buildClient :: ClientBuilder -> <Proc> Client
     statusMessageOf :: Response -> <Proc> String
     asyncInvoke :: Invocation -> ResponseHandler -> FailureHandler -> <Proc> Future Response
     trustAllClientBuilder :: <Proc> ClientBuilder
+    onReadProgress :: WebTarget -> (Long -> <Proc> ()) -> <Proc> ()
+    onWriteProgress :: WebTarget -> (Long -> <Proc> ()) -> <Proc> ()
+    possibleContentLengthOf :: Response -> <Proc> 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
index ef42cc8595c3d9c6c4ba30e4edb8682e50c827f3..f99b8c47f7e8673755ff1441c19a7695ab2004e8 100644 (file)
@@ -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<Long, Tuple0> callback) {
+        target.register(new WriteProgressInterceptor(callback));
+    }
+    
+    public static void onReadProgress(WebTarget target, Function1<Long, Tuple0> 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 (file)
index 0000000..6b3d72f
--- /dev/null
@@ -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<Long, Tuple0> callback;
+    
+    public ReadProgressInterceptor(Function1<Long, Tuple0> 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 (file)
index 0000000..ebbc85f
--- /dev/null
@@ -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<Long, Tuple0> callback;
+    
+    public WriteProgressInterceptor(Function1<Long, Tuple0> 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();
+    }
+
+}