You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2020/03/19 13:54:15 UTC
[juneau] branch master updated: JUNEAU-183
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 7f09fc1 JUNEAU-183
7f09fc1 is described below
commit 7f09fc15a10979d68e9430ea30f1fc4cc4933689
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu Mar 19 09:53:59 2020 -0400
JUNEAU-183
Remote methods should support Future return types.
---
juneau-doc/docs/ReleaseNotes/8.1.4.html | 2 +
.../01.RestProxies/02.RemoteMethod.html | 5 +-
.../rest/client2/RemoteMethodAnnotationTest.java | 90 +++++++++++++++++++++-
.../rest/client/remote/RemoteMethodReturn.java | 21 ++++-
.../org/apache/juneau/rest/client2/RestClient.java | 55 ++++++++-----
5 files changed, 148 insertions(+), 25 deletions(-)
diff --git a/juneau-doc/docs/ReleaseNotes/8.1.4.html b/juneau-doc/docs/ReleaseNotes/8.1.4.html
index 0d7cfd8..2c9b6db 100644
--- a/juneau-doc/docs/ReleaseNotes/8.1.4.html
+++ b/juneau-doc/docs/ReleaseNotes/8.1.4.html
@@ -332,6 +332,8 @@
<li>Better integration with HttpClient.
<li>New fluent-style methods with many new convenience methods.
</ul>
+ <li>
+ <ja>@RemoteMethod</ja>-annotated methods can now return {@link java.util.concurrent.Future Futures} for concurrent processing of requests.
</ul>
<h5 class='topic w800'>juneau-doc</h5>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/01.RestProxies/02.RemoteMethod.html b/juneau-doc/docs/Topics/09.juneau-rest-client/01.RestProxies/02.RemoteMethod.html
index 4d62e89..1d97872 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/01.RestProxies/02.RemoteMethod.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/01.RestProxies/02.RemoteMethod.html
@@ -13,6 +13,7 @@
***************************************************************************************************************************/
-->
+{8.1.4-updated}
@RemoteMethod
<p>
@@ -125,7 +126,7 @@
</p>
<ul class='spaced-list'>
<li>
- <jk>void</jk>
+ <jk>void</jk>/{@link java.lang.Void}
- Don't parse any response.
<br>Note that the method will still throw a runtime exception if an error HTTP status is returned.
<li>
@@ -143,6 +144,8 @@
<li>
{@link java.io.InputStream}
- Returns access to the raw input stream of the response.
+ <li>
+ A {@link java.util.concurrent.Future} of anything on this list.
</ul>
<p>
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RemoteMethodAnnotationTest.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RemoteMethodAnnotationTest.java
index 8b590c5..1714af9 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RemoteMethodAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RemoteMethodAnnotationTest.java
@@ -15,6 +15,7 @@ package org.apache.juneau.rest.client2;
import static org.junit.Assert.*;
import java.io.*;
+import java.util.concurrent.*;
import org.apache.http.*;
import org.apache.juneau.http.annotation.Body;
@@ -71,6 +72,15 @@ public class RemoteMethodAnnotationTest {
public String postA02();
}
+ @Remote
+ public static interface A02 {
+ public Future<String> doGet();
+ public Future<String> doGET();
+ public Future<String> doFoo();
+ public Future<String> getA01();
+ public Future<String> postA02();
+ }
+
@Test
public void a01_inferredMethodsAndPaths() throws Exception {
A01 t = MockRemote.build(A01.class, A.class, null);
@@ -81,6 +91,16 @@ public class RemoteMethodAnnotationTest {
assertEquals("baz", t.postA02());
}
+ @Test
+ public void a02_inferredMethodsAndPaths_futures() throws Exception {
+ A02 t = MockRemote.build(A02.class, A.class, null);
+ assertEquals("foo", t.doGet().get());
+ assertEquals("foo", t.doGET().get());
+ assertEquals("qux", t.doFoo().get());
+ assertEquals("bar", t.getA01().get());
+ assertEquals("baz", t.postA02().get());
+ }
+
//=================================================================================================================
// Return types
//=================================================================================================================
@@ -113,13 +133,21 @@ public class RemoteMethodAnnotationTest {
@Remote
public static interface B01 {
public void b01();
-
public String b02();
public HttpResponse b02a();
public Reader b02b();
public InputStream b02c();
}
+ @Remote
+ public static interface B02 {
+ public Future<Void> b01();
+ public Future<String> b02();
+ public Future<HttpResponse> b02a();
+ public Future<Reader> b02b();
+ public Future<InputStream> b02c();
+ }
+
@Test
public void b01_returnTypes() throws Exception {
B01 t = MockRemote.build(B01.class, B.class, null);
@@ -130,6 +158,16 @@ public class RemoteMethodAnnotationTest {
assertEquals("qux", IOUtils.read(t.b02c()));
}
+ @Test
+ public void b02_returnTypes_futures() throws Exception {
+ B02 t = MockRemote.build(B02.class, B.class, null);
+ t.b01().get();
+ assertEquals("foo", t.b02().get());
+ assertEquals("bar", IOUtils.read(t.b02a().get().getEntity().getContent()));
+ assertEquals("baz", IOUtils.read(t.b02b().get()));
+ assertEquals("qux", IOUtils.read(t.b02c().get()));
+ }
+
//=================================================================================================================
// Return types, JSON
//=================================================================================================================
@@ -159,6 +197,22 @@ public class RemoteMethodAnnotationTest {
public InputStream c01d(@Body String foo);
}
+ @Remote
+ public static interface C02 {
+
+ @RemoteMethod(method="POST",path="c01")
+ public Future<String> c01a(@Body String foo);
+
+ @RemoteMethod(method="POST",path="c01")
+ public Future<HttpResponse> c01b(@Body String foo);
+
+ @RemoteMethod(method="POST",path="c01")
+ public Future<Reader> c01c(@Body String foo);
+
+ @RemoteMethod(method="POST",path="c01")
+ public Future<InputStream> c01d(@Body String foo);
+ }
+
@Test
public void c01_returnTypes_json() throws Exception {
C01 t = MockRemote.build(C01.class, C.class, Json.DEFAULT);
@@ -168,6 +222,15 @@ public class RemoteMethodAnnotationTest {
assertEquals("'foo'", IOUtils.read(t.c01d("foo")));
}
+ @Test
+ public void c02_returnTypes_json_futures() throws Exception {
+ C02 t = MockRemote.build(C02.class, C.class, Json.DEFAULT);
+ assertEquals("foo", t.c01a("foo").get());
+ assertEquals("'foo'", IOUtils.read(t.c01b("foo").get().getEntity().getContent()));
+ assertEquals("'foo'", IOUtils.read(t.c01c("foo").get()));
+ assertEquals("'foo'", IOUtils.read(t.c01d("foo").get()));
+ }
+
//=================================================================================================================
// Return types, part serialization
//=================================================================================================================
@@ -198,6 +261,22 @@ public class RemoteMethodAnnotationTest {
public InputStream d01d(@Body String foo);
}
+ @Remote
+ public static interface D02 {
+
+ @RemoteMethod(method="POST",path="d01")
+ public Future<String> d01a(@Body String foo);
+
+ @RemoteMethod(method="POST",path="d01")
+ public Future<HttpResponse> d01b(@Body String foo);
+
+ @RemoteMethod(method="POST",path="d01")
+ public Future<Reader> d01c(@Body String foo);
+
+ @RemoteMethod(method="POST",path="d01")
+ public Future<InputStream> d01d(@Body String foo);
+ }
+
@Test
public void d01_returnTypes_partSerialization() throws Exception {
D01 t = MockRemote.build(D01.class, D.class, OpenApi.DEFAULT);
@@ -206,4 +285,13 @@ public class RemoteMethodAnnotationTest {
assertEquals("foo", IOUtils.read(t.d01c("foo")));
assertEquals("foo", IOUtils.read(t.d01d("foo")));
}
+
+ @Test
+ public void d02_returnTypes_partSerialization_futures() throws Exception {
+ D02 t = MockRemote.build(D02.class, D.class, OpenApi.DEFAULT);
+ assertEquals("foo", t.d01a("foo").get());
+ assertEquals("foo", IOUtils.read(t.d01b("foo").get().getEntity().getContent()));
+ assertEquals("foo", IOUtils.read(t.d01c("foo").get()));
+ assertEquals("foo", IOUtils.read(t.d01d("foo").get()));
+ }
}
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodReturn.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodReturn.java
index 2f5d6eb..7e68be1 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodReturn.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodReturn.java
@@ -13,6 +13,7 @@
package org.apache.juneau.rest.client.remote;
import java.lang.reflect.*;
+import java.util.concurrent.*;
import org.apache.juneau.*;
import org.apache.juneau.http.remote.RemoteMethod;
@@ -33,6 +34,7 @@ public final class RemoteMethodReturn {
private final Type returnType;
private final RemoteReturn returnValue;
private final ResponseBeanMeta meta;
+ private boolean isFuture;
@SuppressWarnings("deprecation")
RemoteMethodReturn(MethodInfo m) {
@@ -46,7 +48,13 @@ public final class RemoteMethodReturn {
rm = m.getResolvedReturnType().getLastAnnotation(RemoteMethod.class);
RemoteReturn rv = null;
- if (rt.is(void.class))
+
+ if (rt.is(Future.class)) {
+ isFuture = true;
+ Type t = ((ParameterizedType)rt.innerType()).getActualTypeArguments()[0];
+ rt = ClassInfo.of(t);
+ }
+ if (rt.is(void.class) || rt.is(Void.class))
rv = RemoteReturn.NONE;
else if (orm != null)
switch (orm.returns()) {
@@ -67,7 +75,7 @@ public final class RemoteMethodReturn {
this.meta = null;
}
- this.returnType = m.getReturnType().innerType();
+ this.returnType = rt.innerType();
this.returnValue = rv;
}
@@ -90,6 +98,15 @@ public final class RemoteMethodReturn {
}
/**
+ * Returns <jk>true</jk> if the return is wrapped in a {@link Future}.
+ *
+ * @return <jk>true</jk> if the return is wrapped in a {@link Future}.
+ */
+ public boolean isFuture() {
+ return isFuture;
+ }
+
+ /**
* Specifies whether the return value is the body of the request or the HTTP status.
*
* @return The type of value returned.
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
index 16f0f3b..a3e12b9 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
@@ -2615,29 +2615,17 @@ public class RestClient extends BeanContext implements HttpClient, Closeable {
}
RemoteMethodReturn rmr = rmm.getReturns();
- if (rmr.getReturnValue() == RemoteReturn.NONE) {
- rc.complete();
- return null;
- } else if (rmr.getReturnValue() == RemoteReturn.STATUS) {
- rc.ignoreErrors();
- int returnCode = rc.complete().getStatusCode();
- Class<?> rt = method.getReturnType();
- if (rt == Integer.class || rt == int.class)
- return returnCode;
- if (rt == Boolean.class || rt == boolean.class)
- return returnCode < 400;
- throw new RestCallException("Invalid return type on method annotated with @RemoteMethod(returns=HTTP_STATUS). Only integer and booleans types are valid.");
- } else if (rmr.getReturnValue() == RemoteReturn.BEAN) {
- rc.ignoreErrors();
- return rc.run().as(rmr.getResponseBeanMeta());
- } else {
- rc.ignoreErrors();
- Object v = rc.run().getBody().as(rmr.getReturnType());
- if (v == null && method.getReturnType().isPrimitive())
- v = ClassInfo.of(method.getReturnType()).getPrimitiveDefault();
- return v;
+ if (rmr.isFuture()) {
+ return getExecutorService(true).submit(new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ return executeRemote(rc, method, rmr);
+ }
+ });
}
+ return executeRemote(rc, method, rmr);
+
} catch (RestCallException e) {
// Try to throw original exception if possible.
e.throwServerException(interfaceClass.getClassLoader(), rmm.getExceptions());
@@ -2652,6 +2640,31 @@ public class RestClient extends BeanContext implements HttpClient, Closeable {
}
}
+ Object executeRemote(RestRequest rc, Method method, RemoteMethodReturn rmr) throws RestCallException {
+ if (rmr.getReturnValue() == RemoteReturn.NONE) {
+ rc.complete();
+ return null;
+ } else if (rmr.getReturnValue() == RemoteReturn.STATUS) {
+ rc.ignoreErrors();
+ int returnCode = rc.complete().getStatusCode();
+ Class<?> rt = method.getReturnType();
+ if (rt == Integer.class || rt == int.class)
+ return returnCode;
+ if (rt == Boolean.class || rt == boolean.class)
+ return returnCode < 400;
+ throw new RestCallException("Invalid return type on method annotated with @RemoteMethod(returns=HTTP_STATUS). Only integer and booleans types are valid.");
+ } else if (rmr.getReturnValue() == RemoteReturn.BEAN) {
+ rc.ignoreErrors();
+ return rc.run().as(rmr.getResponseBeanMeta());
+ } else {
+ rc.ignoreErrors();
+ Object v = rc.run().getBody().as(rmr.getReturnType());
+ if (v == null && method.getReturnType().isPrimitive())
+ v = ClassInfo.of(method.getReturnType()).getPrimitiveDefault();
+ return v;
+ }
+ }
+
/**
* Create a new Remote Interface against a {@link RemoteInterface @RemoteInterface}-annotated class.
*