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 2017/04/07 21:16:35 UTC
incubator-juneau git commit: Add Future methods to RestCall class for
async handling of HTTP calls.
Repository: incubator-juneau
Updated Branches:
refs/heads/master 7b883daef -> 5b6db82c7
Add Future methods to RestCall class for async handling of HTTP calls.
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/5b6db82c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/5b6db82c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/5b6db82c
Branch: refs/heads/master
Commit: 5b6db82c7c4ec08850e38ea9e34cddb2afd3bcac
Parents: 7b883da
Author: JamesBognar <ja...@apache.org>
Authored: Fri Apr 7 17:16:31 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Fri Apr 7 17:16:31 2017 -0400
----------------------------------------------------------------------
juneau-core/src/main/javadoc/overview.html | 8 ++
.../org/apache/juneau/rest/client/RestCall.java | 97 +++++++++++++++++++-
.../apache/juneau/rest/client/RestClient.java | 15 ++-
.../juneau/rest/client/RestClientBuilder.java | 26 +++++-
.../juneau/rest/test/ClientFuturesResource.java | 35 +++++++
.../java/org/apache/juneau/rest/test/Root.java | 1 +
.../juneau/rest/test/ClientFuturesTest.java | 50 ++++++++++
.../org/apache/juneau/rest/test/_TestSuite.java | 1 +
8 files changed, 229 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-core/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/javadoc/overview.html b/juneau-core/src/main/javadoc/overview.html
index afcbb9e..b6b2006 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -5906,6 +5906,14 @@
<li>{@link org.apache.juneau.rest.client.RestCall#userInfo(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#scheme(String)}
</ul>
+ <li>New methods added to allow for asynchronous HTTP calls:
+ <ul>
+ <li>{@link org.apache.juneau.rest.client.RestClientBuilder#executorService(ExecutorService,boolean)}
+ <li>{@link org.apache.juneau.rest.client.RestCall#runFuture()}
+ <li>{@link org.apache.juneau.rest.client.RestCall#getResponseFuture(Class)}
+ <li>{@link org.apache.juneau.rest.client.RestCall#getResponseFuture(Type,Type...)}
+ <li>{@link org.apache.juneau.rest.client.RestCall#getResponseAsStringFuture()}
+ </ul>
</ul>
<h6 class='topic'>org.apache.juneau.microservice</h6>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index e1aec11..3e36cf3 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -16,6 +16,7 @@ import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
+import java.util.concurrent.*;
import java.util.logging.*;
import java.util.regex.*;
@@ -80,6 +81,7 @@ public final class RestCall {
private Serializer serializer;
private Parser parser;
private URIBuilder uriBuilder;
+ private final ExecutorService executorService;
/**
* Constructs a REST call with the specified method name.
@@ -99,6 +101,7 @@ public final class RestCall {
this.retryInterval = client.retryInterval;
this.serializer = client.serializer;
this.parser = client.parser;
+ this.executorService = client.executorService;
uriBuilder = new URIBuilder(uri);
}
@@ -1017,7 +1020,7 @@ public final class RestCall {
* }
* </p>
*
- * @return This object (for method chaining).
+ * @return The HTTP status code.
* @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
*/
public int run() throws RestCallException {
@@ -1042,6 +1045,25 @@ public final class RestCall {
}
/**
+ * Same as {@link #run()} but allows you to run the call asynchronously.
+ * <p>
+ * This method cannot be used unless the executor service was defined on the client using {@link RestClientBuilder#executorService(ExecutorService,boolean)}.
+ *
+ * @return The HTTP status code.
+ * @throws RestCallException If the executor service was not defined.
+ */
+ public Future<Integer> runFuture() throws RestCallException {
+ return getExecutorService().submit(
+ new Callable<Integer>() {
+ @Override /* Callable */
+ public Integer call() throws Exception {
+ return run();
+ }
+ }
+ );
+ }
+
+ /**
* Connects to the REST resource.
* <p>
* If this is a <code>PUT</code> or <code>POST</code>, also sends the input to the remote resource.<br>
@@ -1303,6 +1325,25 @@ public final class RestCall {
}
/**
+ * Same as {@link #getResponse(Class)} but allows you to run the call asynchronously.
+ * <p>
+ * This method cannot be used unless the executor service was defined on the client using {@link RestClientBuilder#executorService(ExecutorService,boolean)}.
+ *
+ * @return The response as a string.
+ * @throws RestCallException If the executor service was not defined.
+ */
+ public Future<String> getResponseAsStringFuture() throws RestCallException {
+ return getExecutorService().submit(
+ new Callable<String>() {
+ @Override /* Callable */
+ public String call() throws Exception {
+ return getResponseAsString();
+ }
+ }
+ );
+ }
+
+ /**
* Same as {@link #getResponse(Type, Type...)} except optimized for a non-parameterized class.
* <p>
* This is the preferred parse method for simple types since you don't need to cast the results.
@@ -1339,6 +1380,28 @@ public final class RestCall {
}
/**
+ * Same as {@link #getResponse(Class)} but allows you to run the call asynchronously.
+ * <p>
+ * This method cannot be used unless the executor service was defined on the client using {@link RestClientBuilder#executorService(ExecutorService,boolean)}.
+ *
+ * @param <T> The class type of the object being created.
+ * See {@link #getResponse(Type, Type...)} for details.
+ * @param type The object type to create.
+ * @return The parsed object.
+ * @throws RestCallException If the executor service was not defined.
+ */
+ public <T> Future<T> getResponseFuture(final Class<T> type) throws RestCallException {
+ return getExecutorService().submit(
+ new Callable<T>() {
+ @Override /* Callable */
+ public T call() throws Exception {
+ return getResponse(type);
+ }
+ }
+ );
+ }
+
+ /**
* Parses HTTP body into the specified object type.
* The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
*
@@ -1391,6 +1454,32 @@ public final class RestCall {
}
/**
+ * Same as {@link #getResponse(Class)} but allows you to run the call asynchronously.
+ * <p>
+ * This method cannot be used unless the executor service was defined on the client using {@link RestClientBuilder#executorService(ExecutorService,boolean)}.
+ *
+ * @param <T> The class type of the object being created.
+ * See {@link #getResponse(Type, Type...)} for details.
+ * @param type The object type to create.
+ * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
+ * @param args The type arguments of the class if it's a collection or map.
+ * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
+ * <br>Ignored if the main type is not a map or collection.
+ * @return The parsed object.
+ * @throws RestCallException If the executor service was not defined.
+ */
+ public <T> Future<T> getResponseFuture(final Type type, final Type...args) throws RestCallException {
+ return getExecutorService().submit(
+ new Callable<T>() {
+ @Override /* Callable */
+ public T call() throws Exception {
+ return getResponse(type, args);
+ }
+ }
+ );
+ }
+
+ /**
* Parses the output from the connection into the specified type and then wraps that in a {@link PojoRest}.
* <p>
* Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
@@ -1502,6 +1591,12 @@ public final class RestCall {
return this;
}
+ private ExecutorService getExecutorService() throws RestCallException {
+ if (executorService == null)
+ throw new RestCallException("Future method cannot be called. Executor service was not defined via the RestClientBuilder.executorService() method.");
+ return executorService;
+ }
+
/**
* Adds a {@link RestCallLogger} to the list of interceptors on this class.
*
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index bbdb98e..12b578f 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -67,6 +67,8 @@ public class RestClient extends CoreObject {
final long retryInterval;
final boolean debug;
final RestCallInterceptor[] interceptors;
+ final ExecutorService executorService;
+ final boolean executorServiceShutdownOnClose;
/**
* Create a new REST client.
@@ -85,6 +87,8 @@ public class RestClient extends CoreObject {
* @param retries
* @param retryInterval
* @param debug
+ * @param executorService
+ * @param executorServiceShutdownOnClose
*/
public RestClient(
PropertyStore propertyStore,
@@ -101,7 +105,9 @@ public class RestClient extends CoreObject {
RetryOn retryOn,
int retries,
long retryInterval,
- boolean debug) {
+ boolean debug,
+ ExecutorService executorService,
+ boolean executorServiceShutdownOnClose) {
super(propertyStore);
this.httpClient = httpClient;
this.keepHttpClientOpen = keepHttpClientOpen;
@@ -129,6 +135,9 @@ public class RestClient extends CoreObject {
creationStack = Thread.currentThread().getStackTrace();
else
creationStack = null;
+
+ this.executorService = executorService;
+ this.executorServiceShutdownOnClose = executorServiceShutdownOnClose;
}
/**
@@ -141,6 +150,8 @@ public class RestClient extends CoreObject {
isClosed = true;
if (httpClient != null && ! keepHttpClientOpen)
httpClient.close();
+ if (executorService != null && executorServiceShutdownOnClose)
+ executorService.shutdown();
if (Boolean.getBoolean("org.apache.juneau.rest.client.RestClient.trackLifecycle"))
closedStack = Thread.currentThread().getStackTrace();
}
@@ -153,6 +164,8 @@ public class RestClient extends CoreObject {
try {
if (httpClient != null && ! keepHttpClientOpen)
httpClient.close();
+ if (executorService != null && executorServiceShutdownOnClose)
+ executorService.shutdown();
} catch (Throwable t) {}
if (Boolean.getBoolean("org.apache.juneau.rest.client.RestClient.trackLifecycle"))
closedStack = Thread.currentThread().getStackTrace();
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 869b922..70f6970 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -76,7 +76,8 @@ public class RestClientBuilder extends CoreObjectBuilder {
private int retries = 1;
private long retryInterval = -1;
private RetryOn retryOn = RetryOn.DEFAULT;
- private boolean debug;
+ private boolean debug, executorServiceShutdownOnClose;
+ private ExecutorService executorService;
/**
* Constructor, default settings.
@@ -140,7 +141,7 @@ public class RestClientBuilder extends CoreObjectBuilder {
UrlEncodingSerializer us = new SerializerBuilder(propertyStore).build(UrlEncodingSerializer.class);
- return new RestClient(propertyStore, httpClient, keepHttpClientOpen, s, p, us, headers, interceptors, remoteableServletUri, remoteableServiceUriMap, rootUrl, retryOn, retries, retryInterval, debug);
+ return new RestClient(propertyStore, httpClient, keepHttpClientOpen, s, p, us, headers, interceptors, remoteableServletUri, remoteableServiceUriMap, rootUrl, retryOn, retries, retryInterval, debug, executorService, executorServiceShutdownOnClose);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -425,6 +426,27 @@ public class RestClientBuilder extends CoreObjectBuilder {
return this;
}
+ /**
+ * Defines the executor service to use when calling future methods on the {@link RestCall} class.
+ * <p>
+ * You must specify the executor service if you want to use any of the following methods:
+ * <ul>
+ * <li>{@link RestCall#runFuture()}
+ * <li>{@link RestCall#getResponseFuture(Class)}
+ * <li>{@link RestCall#getResponseFuture(Type,Type...)}
+ * <li>{@link RestCall#getResponseAsString()}
+ * </ul>
+ *
+ * @param executorService The executor service.
+ * @param shutdownOnClose Call {@link ExecutorService#shutdown()} when {@link RestClient#close()} is called.
+ * @return This object (for method chaining).
+ */
+ public RestClientBuilder executorService(ExecutorService executorService, boolean shutdownOnClose) {
+ this.executorService = executorService;
+ this.executorServiceShutdownOnClose = shutdownOnClose;
+ return this;
+ }
+
//--------------------------------------------------------------------------------
// HTTP headers
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ClientFuturesResource.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ClientFuturesResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ClientFuturesResource.java
new file mode 100644
index 0000000..0a4202a
--- /dev/null
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ClientFuturesResource.java
@@ -0,0 +1,35 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.test;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * JUnit automated testcase resource.
+ */
+@RestResource(
+ path="/testClientFutures"
+)
+public class ClientFuturesResource extends RestServletDefault {
+ private static final long serialVersionUID = 1L;
+
+ //====================================================================================================
+ // Test GET
+ //====================================================================================================
+ @RestMethod(name="GET", path="/")
+ public ObjectMap test1(RestRequest req) throws Exception {
+ return new ObjectMap().append("foo","bar");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
index 10bbb18..fabb545 100644
--- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
@@ -24,6 +24,7 @@ import org.apache.juneau.rest.labels.*;
BeanContextPropertiesResource.class,
CallbackStringsResource.class,
CharsetEncodingsResource.class,
+ ClientFuturesResource.class,
ClientVersionResource.class,
ConfigResource.class,
ContentResource.class,
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ClientFuturesTest.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ClientFuturesTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ClientFuturesTest.java
new file mode 100644
index 0000000..b361ba5
--- /dev/null
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ClientFuturesTest.java
@@ -0,0 +1,50 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.test;
+
+import static org.apache.juneau.rest.test.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.concurrent.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.client.*;
+import org.junit.*;
+
+public class ClientFuturesTest extends RestTestcase {
+
+ private static String URL = "/testClientFutures";
+
+ //====================================================================================================
+ // Basic tests
+ //====================================================================================================
+ @Test
+ public void test() throws Exception {
+ RestClient client = null;
+ try {
+ ExecutorService es = new ThreadPoolExecutor(1, 1, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1));
+ client = TestMicroservice.client().executorService(es, true).build();
+
+ Future<Integer> f = client.doGet(URL).runFuture();
+ assertEquals(200, f.get().intValue());
+
+ Future<ObjectMap> f2 = client.doGet(URL).getResponseFuture(ObjectMap.class);
+ assertObjectEquals("{foo:'bar'}", f2.get());
+
+ Future<String> f3 = client.doGet(URL).getResponseAsStringFuture();
+ assertObjectEquals("'{\"foo\":\"bar\"}'", f3.get());
+ } finally {
+ client.closeQuietly();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/5b6db82c/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
index 0714aca..ec817ff 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
@@ -28,6 +28,7 @@ import org.junit.runners.Suite.*;
BeanContextPropertiesTest.class,
CallbackStringsTest.class,
CharsetEncodingsTest.class,
+ ClientFuturesTest.class,
ClientVersionTest.class,
ConfigTest.class,
ContentTest.class,