Remove AsyncRestTemplate and related types
This commit is contained in:
parent
932291b867
commit
e3b48c23dd
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.mock.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
/**
|
||||
* An extension of {@link MockClientHttpRequest} that also implements
|
||||
* {@link org.springframework.http.client.AsyncClientHttpRequest} by wrapping the response in a
|
||||
* {@link SettableListenableFuture}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public class MockAsyncClientHttpRequest extends MockClientHttpRequest implements org.springframework.http.client.AsyncClientHttpRequest {
|
||||
|
||||
public MockAsyncClientHttpRequest() {
|
||||
}
|
||||
|
||||
public MockAsyncClientHttpRequest(HttpMethod httpMethod, URI uri) {
|
||||
super(httpMethod, uri);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ListenableFuture<ClientHttpResponse> executeAsync() throws IOException {
|
||||
SettableListenableFuture<ClientHttpResponse> future = new SettableListenableFuture<>();
|
||||
future.set(execute());
|
||||
return future;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.test.web.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
@ -39,18 +38,10 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
|||
/**
|
||||
* A {@link ClientHttpRequestFactory} for requests executed via {@link MockMvc}.
|
||||
*
|
||||
* <p>As of 5.0 this class also implements
|
||||
* {@link org.springframework.http.client.AsyncClientHttpRequestFactory
|
||||
* AsyncClientHttpRequestFactory}. However note that
|
||||
* {@link org.springframework.web.client.AsyncRestTemplate} and related classes
|
||||
* have been deprecated at the same time.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MockMvcClientHttpRequestFactory
|
||||
implements ClientHttpRequestFactory, org.springframework.http.client.AsyncClientHttpRequestFactory {
|
||||
public class MockMvcClientHttpRequestFactory implements ClientHttpRequestFactory {
|
||||
|
||||
private final MockMvc mockMvc;
|
||||
|
||||
|
@ -65,22 +56,12 @@ public class MockMvcClientHttpRequestFactory
|
|||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
|
||||
return new MockClientHttpRequest(httpMethod, uri) {
|
||||
@Override
|
||||
public ClientHttpResponse executeInternal() throws IOException {
|
||||
public ClientHttpResponse executeInternal() {
|
||||
return getClientHttpResponse(httpMethod, uri, getHeaders(), getBodyAsBytes());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.springframework.http.client.AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod method) {
|
||||
return new org.springframework.mock.http.client.MockAsyncClientHttpRequest(method, uri) {
|
||||
@Override
|
||||
protected ClientHttpResponse executeInternal() throws IOException {
|
||||
return getClientHttpResponse(method, uri, getHeaders(), getBodyAsBytes());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ClientHttpResponse getClientHttpResponse(
|
||||
HttpMethod httpMethod, URI uri, HttpHeaders requestHeaders, byte[] requestBody) {
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.springframework.http.client.BufferingClientHttpRequestFactory;
|
|||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.http.client.MockClientHttpRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.client.support.RestGatewaySupport;
|
||||
|
@ -64,7 +64,6 @@ import org.springframework.web.client.support.RestGatewaySupport;
|
|||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class MockRestServiceServer {
|
||||
|
||||
private final RequestExpectationManager expectationManager;
|
||||
|
@ -147,18 +146,6 @@ public final class MockRestServiceServer {
|
|||
return new DefaultBuilder(restTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder for a {@code MockRestServiceServer} that should be used
|
||||
* to reply to the given {@code AsyncRestTemplate}.
|
||||
* @since 4.3
|
||||
* @deprecated see deprecation notice on
|
||||
* {@link org.springframework.web.client.AsyncRestTemplate} itself
|
||||
*/
|
||||
@Deprecated
|
||||
public static MockRestServiceServerBuilder bindTo(org.springframework.web.client.AsyncRestTemplate asyncRestTemplate) {
|
||||
return new DefaultBuilder(asyncRestTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder for a {@code MockRestServiceServer} that should be used
|
||||
* to reply to the given {@code RestGatewaySupport}.
|
||||
|
@ -179,18 +166,6 @@ public final class MockRestServiceServer {
|
|||
return bindTo(restTemplate).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@code bindTo(asyncRestTemplate).build()}.
|
||||
* @param asyncRestTemplate the AsyncRestTemplate to set up for mock testing
|
||||
* @return the created mock server
|
||||
* @deprecated see deprecation notice on
|
||||
* {@link org.springframework.web.client.AsyncRestTemplate} itself
|
||||
*/
|
||||
@Deprecated
|
||||
public static MockRestServiceServer createServer(org.springframework.web.client.AsyncRestTemplate asyncRestTemplate) {
|
||||
return bindTo(asyncRestTemplate).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@code bindTo(restGateway).build()}.
|
||||
* @param restGateway the REST gateway to set up for mock testing
|
||||
|
@ -226,8 +201,8 @@ public final class MockRestServiceServer {
|
|||
|
||||
/**
|
||||
* Build the {@code MockRestServiceServer} and set up the underlying
|
||||
* {@code RestTemplate} or {@code AsyncRestTemplate} with a
|
||||
* {@link ClientHttpRequestFactory} that creates mock requests.
|
||||
* {@code RestTemplate} with a {@link ClientHttpRequestFactory} that
|
||||
* creates mock requests.
|
||||
*/
|
||||
MockRestServiceServer build();
|
||||
|
||||
|
@ -241,12 +216,8 @@ public final class MockRestServiceServer {
|
|||
|
||||
private static class DefaultBuilder implements MockRestServiceServerBuilder {
|
||||
|
||||
@Nullable
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
@Nullable
|
||||
private final org.springframework.web.client.AsyncRestTemplate asyncRestTemplate;
|
||||
|
||||
private boolean ignoreExpectOrder;
|
||||
|
||||
private boolean bufferContent;
|
||||
|
@ -255,13 +226,6 @@ public final class MockRestServiceServer {
|
|||
public DefaultBuilder(RestTemplate restTemplate) {
|
||||
Assert.notNull(restTemplate, "RestTemplate must not be null");
|
||||
this.restTemplate = restTemplate;
|
||||
this.asyncRestTemplate = null;
|
||||
}
|
||||
|
||||
public DefaultBuilder(org.springframework.web.client.AsyncRestTemplate asyncRestTemplate) {
|
||||
Assert.notNull(asyncRestTemplate, "AsyncRestTemplate must not be null");
|
||||
this.restTemplate = null;
|
||||
this.asyncRestTemplate = asyncRestTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -290,16 +254,11 @@ public final class MockRestServiceServer {
|
|||
public MockRestServiceServer build(RequestExpectationManager manager) {
|
||||
MockRestServiceServer server = new MockRestServiceServer(manager);
|
||||
MockClientHttpRequestFactory factory = server.new MockClientHttpRequestFactory();
|
||||
if (this.restTemplate != null) {
|
||||
if (this.bufferContent) {
|
||||
this.restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
|
||||
}
|
||||
else {
|
||||
this.restTemplate.setRequestFactory(factory);
|
||||
}
|
||||
if (this.bufferContent) {
|
||||
this.restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
|
||||
}
|
||||
if (this.asyncRestTemplate != null) {
|
||||
this.asyncRestTemplate.setAsyncRequestFactory(factory);
|
||||
else {
|
||||
this.restTemplate.setRequestFactory(factory);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
@ -310,28 +269,18 @@ public final class MockRestServiceServer {
|
|||
* Mock ClientHttpRequestFactory that creates requests by iterating
|
||||
* over the list of expected {@link DefaultRequestExpectation}'s.
|
||||
*/
|
||||
private class MockClientHttpRequestFactory implements ClientHttpRequestFactory,
|
||||
org.springframework.http.client.AsyncClientHttpRequestFactory {
|
||||
private class MockClientHttpRequestFactory implements ClientHttpRequestFactory {
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
|
||||
return createRequestInternal(uri, httpMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.springframework.http.client.AsyncClientHttpRequest createAsyncRequest(
|
||||
URI uri, HttpMethod httpMethod) {
|
||||
|
||||
return createRequestInternal(uri, httpMethod);
|
||||
}
|
||||
|
||||
private org.springframework.mock.http.client.MockAsyncClientHttpRequest createRequestInternal(
|
||||
URI uri, HttpMethod httpMethod) {
|
||||
|
||||
private MockClientHttpRequest createRequestInternal(URI uri, HttpMethod httpMethod) {
|
||||
Assert.notNull(uri, "'uri' must not be null");
|
||||
Assert.notNull(httpMethod, "'httpMethod' must not be null");
|
||||
|
||||
return new org.springframework.mock.http.client.MockAsyncClientHttpRequest(httpMethod, uri) {
|
||||
return new MockClientHttpRequest(httpMethod, uri) {
|
||||
|
||||
@Override
|
||||
protected ClientHttpResponse executeInternal() throws IOException {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -23,10 +23,10 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.mock.http.client.MockClientHttpRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.http.HttpMethod.GET;
|
||||
import static org.springframework.http.HttpMethod.POST;
|
||||
import static org.springframework.test.web.client.ExpectedCount.once;
|
||||
import static org.springframework.test.web.client.ExpectedCount.twice;
|
||||
|
@ -44,15 +44,15 @@ public class DefaultRequestExpectationTests {
|
|||
@Test
|
||||
public void match() throws Exception {
|
||||
RequestExpectation expectation = new DefaultRequestExpectation(once(), requestTo("/foo"));
|
||||
expectation.match(createRequest(GET, "/foo"));
|
||||
expectation.match(createRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchWithFailedExpectation() throws Exception {
|
||||
public void matchWithFailedExpectation() {
|
||||
RequestExpectation expectation = new DefaultRequestExpectation(once(), requestTo("/foo"));
|
||||
expectation.andExpect(method(POST));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
|
||||
expectation.match(createRequest(GET, "/foo")))
|
||||
expectation.match(createRequest()))
|
||||
.withMessageContaining("Unexpected HttpMethod expected:<POST> but was:<GET>");
|
||||
}
|
||||
|
||||
|
@ -81,10 +81,9 @@ public class DefaultRequestExpectationTests {
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private ClientHttpRequest createRequest(HttpMethod method, String url) {
|
||||
private ClientHttpRequest createRequest() {
|
||||
try {
|
||||
return new org.springframework.mock.http.client.MockAsyncClientHttpRequest(method, new URI(url));
|
||||
return new MockClientHttpRequest(HttpMethod.GET, new URI("/foo"));
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.mock.http.client.MockClientHttpRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
@ -42,7 +43,7 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
|||
*/
|
||||
public class UnorderedRequestExpectationManagerTests {
|
||||
|
||||
private UnorderedRequestExpectationManager manager = new UnorderedRequestExpectationManager();
|
||||
private final UnorderedRequestExpectationManager manager = new UnorderedRequestExpectationManager();
|
||||
|
||||
|
||||
@Test
|
||||
|
@ -57,7 +58,7 @@ public class UnorderedRequestExpectationManagerTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void zeroExpectedRequests() throws Exception {
|
||||
public void zeroExpectedRequests() {
|
||||
this.manager.verify();
|
||||
}
|
||||
|
||||
|
@ -108,19 +109,18 @@ public class UnorderedRequestExpectationManagerTests {
|
|||
this.manager.validateRequest(createRequest(GET, "/bar"));
|
||||
this.manager.validateRequest(createRequest(GET, "/foo"));
|
||||
this.manager.validateRequest(createRequest(GET, "/foo"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
|
||||
this.manager.verify())
|
||||
.withMessageContaining("3 request(s) executed:\n" +
|
||||
"GET /bar\n" +
|
||||
"GET /foo\n" +
|
||||
"GET /foo\n");
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(this.manager::verify)
|
||||
.withMessageContaining("3 request(s) executed:\n" +
|
||||
"GET /bar\n" +
|
||||
"GET /foo\n" +
|
||||
"GET /foo\n");
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private ClientHttpRequest createRequest(HttpMethod method, String url) {
|
||||
try {
|
||||
return new org.springframework.mock.http.client.MockAsyncClientHttpRequest(method, new URI(url));
|
||||
return new MockClientHttpRequest(method, new URI(url));
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -23,7 +23,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
@ -31,7 +30,6 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
|||
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
@ -68,21 +66,12 @@ public class MockMvcClientHttpRequestFactoryTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
public void test() {
|
||||
RestTemplate template = new RestTemplate(new MockMvcClientHttpRequestFactory(this.mockMvc));
|
||||
String result = template.getForObject("/foo", String.class);
|
||||
assertThat(result).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testAsyncTemplate() throws Exception {
|
||||
org.springframework.web.client.AsyncRestTemplate template = new org.springframework.web.client.AsyncRestTemplate(
|
||||
new MockMvcClientHttpRequestFactory(this.mockMvc));
|
||||
ListenableFuture<ResponseEntity<String>> entity = template.getForEntity("/foo", String.class);
|
||||
assertThat(entity.get().getBody()).isEqualTo("bar");
|
||||
}
|
||||
|
||||
|
||||
@EnableWebMvc
|
||||
@Configuration
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.test.web.client.samples;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.client.ExpectedCount.manyTimes;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
||||
|
||||
/**
|
||||
* Examples to demonstrate writing client-side REST tests with Spring MVC Test.
|
||||
* While the tests in this class invoke the RestTemplate directly, in actual
|
||||
* tests the RestTemplate may likely be invoked indirectly, i.e. through client
|
||||
* code.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SampleAsyncTests {
|
||||
|
||||
private final org.springframework.web.client.AsyncRestTemplate restTemplate = new org.springframework.web.client.AsyncRestTemplate();
|
||||
|
||||
private final MockRestServiceServer mockServer = MockRestServiceServer.createServer(this.restTemplate);
|
||||
|
||||
|
||||
@Test
|
||||
public void performGet() throws Exception {
|
||||
|
||||
String responseBody = "{\"name\" : \"Ludwig van Beethoven\", \"someDouble\" : \"1.6035\"}";
|
||||
|
||||
this.mockServer.expect(requestTo("/composers/42")).andExpect(method(HttpMethod.GET))
|
||||
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
ListenableFuture<ResponseEntity<Person>> ludwig =
|
||||
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
|
||||
|
||||
// We are only validating the request. The response is mocked out.
|
||||
// person.getName().equals("Ludwig van Beethoven")
|
||||
// person.getDouble().equals(1.6035)
|
||||
|
||||
this.mockServer.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performGetManyTimes() throws Exception {
|
||||
|
||||
String responseBody = "{\"name\" : \"Ludwig van Beethoven\", \"someDouble\" : \"1.6035\"}";
|
||||
|
||||
this.mockServer.expect(manyTimes(), requestTo("/composers/42")).andExpect(method(HttpMethod.GET))
|
||||
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
ListenableFuture<ResponseEntity<Person>> ludwig =
|
||||
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
|
||||
|
||||
// We are only validating the request. The response is mocked out.
|
||||
// person.getName().equals("Ludwig van Beethoven")
|
||||
// person.getDouble().equals(1.6035)
|
||||
|
||||
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
|
||||
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
|
||||
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
|
||||
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
|
||||
|
||||
this.mockServer.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performGetWithResponseBodyFromFile() throws Exception {
|
||||
|
||||
Resource responseBody = new ClassPathResource("ludwig.json", this.getClass());
|
||||
|
||||
this.mockServer.expect(requestTo("/composers/42")).andExpect(method(HttpMethod.GET))
|
||||
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
ListenableFuture<ResponseEntity<Person>> ludwig =
|
||||
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
|
||||
|
||||
// hotel.getId() == 42
|
||||
// hotel.getName().equals("Holiday Inn")
|
||||
|
||||
this.mockServer.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verify() {
|
||||
|
||||
this.mockServer.expect(requestTo("/number")).andExpect(method(HttpMethod.GET))
|
||||
.andRespond(withSuccess("1", MediaType.TEXT_PLAIN));
|
||||
|
||||
this.mockServer.expect(requestTo("/number")).andExpect(method(HttpMethod.GET))
|
||||
.andRespond(withSuccess("2", MediaType.TEXT_PLAIN));
|
||||
|
||||
this.mockServer.expect(requestTo("/number")).andExpect(method(HttpMethod.GET))
|
||||
.andRespond(withSuccess("4", MediaType.TEXT_PLAIN));
|
||||
|
||||
this.mockServer.expect(requestTo("/number")).andExpect(method(HttpMethod.GET))
|
||||
.andRespond(withSuccess("8", MediaType.TEXT_PLAIN));
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
ListenableFuture<ResponseEntity<String>> result = this.restTemplate.getForEntity("/number", String.class);
|
||||
// result == "1"
|
||||
|
||||
result = this.restTemplate.getForEntity("/number", String.class);
|
||||
// result == "2"
|
||||
|
||||
try {
|
||||
this.mockServer.verify();
|
||||
}
|
||||
catch (AssertionError error) {
|
||||
assertThat(error.getMessage().contains("2 unsatisfied expectation(s)")).as(error.getMessage()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Abstract base for {@link AsyncClientHttpRequest} that makes sure that headers and body
|
||||
* are not written multiple times.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.http.client.reactive.AbstractClientHttpRequest}
|
||||
*/
|
||||
@Deprecated
|
||||
abstract class AbstractAsyncClientHttpRequest implements AsyncClientHttpRequest {
|
||||
|
||||
private final HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
private boolean executed = false;
|
||||
|
||||
|
||||
@Override
|
||||
public final HttpHeaders getHeaders() {
|
||||
return (this.executed ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final OutputStream getBody() throws IOException {
|
||||
assertNotExecuted();
|
||||
return getBodyInternal(this.headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<ClientHttpResponse> executeAsync() throws IOException {
|
||||
assertNotExecuted();
|
||||
ListenableFuture<ClientHttpResponse> result = executeInternal(this.headers);
|
||||
this.executed = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that this request has not been {@linkplain #executeAsync() executed} yet.
|
||||
* @throws IllegalStateException if this request has been executed
|
||||
*/
|
||||
protected void assertNotExecuted() {
|
||||
Assert.state(!this.executed, "ClientHttpRequest already executed");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abstract template method that returns the body.
|
||||
* @param headers the HTTP headers
|
||||
* @return the body output stream
|
||||
*/
|
||||
protected abstract OutputStream getBodyInternal(HttpHeaders headers) throws IOException;
|
||||
|
||||
/**
|
||||
* Abstract template method that writes the given headers and content to the HTTP request.
|
||||
* @param headers the HTTP headers
|
||||
* @return the response object for the executed request
|
||||
*/
|
||||
protected abstract ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers)
|
||||
throws IOException;
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link AsyncClientHttpRequest} that buffers output
|
||||
* in a byte array before sending it over the wire.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
abstract class AbstractBufferingAsyncClientHttpRequest extends AbstractAsyncClientHttpRequest {
|
||||
|
||||
private ByteArrayOutputStream bufferedOutput = new ByteArrayOutputStream(1024);
|
||||
|
||||
|
||||
@Override
|
||||
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
|
||||
return this.bufferedOutput;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers) throws IOException {
|
||||
byte[] bytes = this.bufferedOutput.toByteArray();
|
||||
if (headers.getContentLength() < 0) {
|
||||
headers.setContentLength(bytes.length);
|
||||
}
|
||||
ListenableFuture<ClientHttpResponse> result = executeInternal(headers, bytes);
|
||||
this.bufferedOutput = new ByteArrayOutputStream(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract template method that writes the given headers and content to the HTTP request.
|
||||
* @param headers the HTTP headers
|
||||
* @param bufferedOutput the body content
|
||||
* @return the response object for the executed request
|
||||
*/
|
||||
protected abstract ListenableFuture<ClientHttpResponse> executeInternal(
|
||||
HttpHeaders headers, byte[] bufferedOutput) throws IOException;
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Represents a client-side asynchronous HTTP request. Created via an
|
||||
* implementation of the {@link AsyncClientHttpRequestFactory}.
|
||||
*
|
||||
* <p>A {@code AsyncHttpRequest} can be {@linkplain #executeAsync() executed},
|
||||
* getting a future {@link ClientHttpResponse} which can be read from.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @see AsyncClientHttpRequestFactory#createAsyncRequest
|
||||
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.web.reactive.function.client.ClientRequest}
|
||||
*/
|
||||
@Deprecated
|
||||
public interface AsyncClientHttpRequest extends HttpRequest, HttpOutputMessage {
|
||||
|
||||
/**
|
||||
* Execute this request asynchronously, resulting in a Future handle.
|
||||
* {@link ClientHttpResponse} that can be read.
|
||||
* @return the future response result of the execution
|
||||
* @throws java.io.IOException in case of I/O errors
|
||||
*/
|
||||
ListenableFuture<ClientHttpResponse> executeAsync() throws IOException;
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Represents the context of a client-side HTTP request execution.
|
||||
*
|
||||
* <p>Used to invoke the next interceptor in the interceptor chain, or -
|
||||
* if the calling interceptor is last - execute the request itself.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
* @see AsyncClientHttpRequestInterceptor
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction}
|
||||
*/
|
||||
@Deprecated
|
||||
public interface AsyncClientHttpRequestExecution {
|
||||
|
||||
/**
|
||||
* Resume the request execution by invoking the next interceptor in the chain
|
||||
* or executing the request to the remote service.
|
||||
* @param request the HTTP request, containing the HTTP method and headers
|
||||
* @param body the body of the request
|
||||
* @return a corresponding future handle
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
ListenableFuture<ClientHttpResponse> executeAsync(HttpRequest request, byte[] body) throws IOException;
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* Factory for {@link AsyncClientHttpRequest} objects.
|
||||
* Requests are created by the {@link #createAsyncRequest(URI, HttpMethod)} method.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.http.client.reactive.ClientHttpConnector}
|
||||
*/
|
||||
@Deprecated
|
||||
public interface AsyncClientHttpRequestFactory {
|
||||
|
||||
/**
|
||||
* Create a new asynchronous {@link AsyncClientHttpRequest} for the specified URI
|
||||
* and HTTP method.
|
||||
* <p>The returned request can be written to, and then executed by calling
|
||||
* {@link AsyncClientHttpRequest#executeAsync()}.
|
||||
* @param uri the URI to create a request for
|
||||
* @param httpMethod the HTTP method to execute
|
||||
* @return the created request
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException;
|
||||
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Intercepts client-side HTTP requests. Implementations of this interface can be
|
||||
* {@linkplain org.springframework.web.client.AsyncRestTemplate#setInterceptors registered}
|
||||
* with the {@link org.springframework.web.client.AsyncRestTemplate} as to modify
|
||||
* the outgoing {@link HttpRequest} and/or register to modify the incoming
|
||||
* {@link ClientHttpResponse} with help of a
|
||||
* {@link org.springframework.util.concurrent.ListenableFutureAdapter}.
|
||||
*
|
||||
* <p>The main entry point for interceptors is {@link #intercept}.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
* @see org.springframework.web.client.AsyncRestTemplate
|
||||
* @see org.springframework.http.client.support.InterceptingAsyncHttpAccessor
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction}
|
||||
*/
|
||||
@Deprecated
|
||||
public interface AsyncClientHttpRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Intercept the given request, and return a response future. The given
|
||||
* {@link AsyncClientHttpRequestExecution} allows the interceptor to pass on
|
||||
* the request to the next entity in the chain.
|
||||
* <p>An implementation might follow this pattern:
|
||||
* <ol>
|
||||
* <li>Examine the {@linkplain HttpRequest request} and body</li>
|
||||
* <li>Optionally {@linkplain org.springframework.http.client.support.HttpRequestWrapper
|
||||
* wrap} the request to filter HTTP attributes.</li>
|
||||
* <li>Optionally modify the body of the request.</li>
|
||||
* <li>One of the following:
|
||||
* <ul>
|
||||
* <li>execute the request through {@link ClientHttpRequestExecution}</li>
|
||||
* <li>don't execute the request to block the execution altogether</li>
|
||||
* </ul>
|
||||
* <li>Optionally adapt the response to filter HTTP attributes with the help of
|
||||
* {@link org.springframework.util.concurrent.ListenableFutureAdapter
|
||||
* ListenableFutureAdapter}.</li>
|
||||
* </ol>
|
||||
* @param request the request, containing method, URI, and headers
|
||||
* @param body the body of the request
|
||||
* @param execution the request execution
|
||||
* @return the response future
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
ListenableFuture<ClientHttpResponse> intercept(HttpRequest request, byte[] body,
|
||||
AsyncClientHttpRequestExecution execution) throws IOException;
|
||||
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.concurrent.FutureCallback;
|
||||
import org.apache.http.nio.client.HttpAsyncClient;
|
||||
import org.apache.http.nio.entity.NByteArrayEntity;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.concurrent.FailureCallback;
|
||||
import org.springframework.util.concurrent.FutureAdapter;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallbackRegistry;
|
||||
import org.springframework.util.concurrent.SuccessCallback;
|
||||
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequest} implementation based on
|
||||
* Apache HttpComponents HttpAsyncClient.
|
||||
*
|
||||
* <p>Created via the {@link HttpComponentsClientHttpRequestFactory}.
|
||||
*
|
||||
* @author Oleg Kalnichevski
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @see HttpComponentsClientHttpRequestFactory#createRequest
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.http.client.reactive.HttpComponentsClientHttpConnector}
|
||||
*/
|
||||
@Deprecated
|
||||
final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
|
||||
|
||||
private final HttpAsyncClient httpClient;
|
||||
|
||||
private final HttpUriRequest httpRequest;
|
||||
|
||||
private final HttpContext httpContext;
|
||||
|
||||
|
||||
HttpComponentsAsyncClientHttpRequest(HttpAsyncClient client, HttpUriRequest request, HttpContext context) {
|
||||
this.httpClient = client;
|
||||
this.httpRequest = request;
|
||||
this.httpContext = context;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return this.httpRequest.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return this.httpRequest.getURI();
|
||||
}
|
||||
|
||||
HttpContext getHttpContext() {
|
||||
return this.httpContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers, byte[] bufferedOutput)
|
||||
throws IOException {
|
||||
|
||||
HttpComponentsClientHttpRequest.addHeaders(this.httpRequest, headers);
|
||||
|
||||
if (this.httpRequest instanceof HttpEntityEnclosingRequest) {
|
||||
HttpEntityEnclosingRequest entityEnclosingRequest = (HttpEntityEnclosingRequest) this.httpRequest;
|
||||
HttpEntity requestEntity = new NByteArrayEntity(bufferedOutput);
|
||||
entityEnclosingRequest.setEntity(requestEntity);
|
||||
}
|
||||
|
||||
HttpResponseFutureCallback callback = new HttpResponseFutureCallback(this.httpRequest);
|
||||
Future<HttpResponse> futureResponse = this.httpClient.execute(this.httpRequest, this.httpContext, callback);
|
||||
return new ClientHttpResponseFuture(futureResponse, callback);
|
||||
}
|
||||
|
||||
|
||||
private static class HttpResponseFutureCallback implements FutureCallback<HttpResponse> {
|
||||
|
||||
private final HttpUriRequest request;
|
||||
|
||||
private final ListenableFutureCallbackRegistry<ClientHttpResponse> callbacks =
|
||||
new ListenableFutureCallbackRegistry<>();
|
||||
|
||||
public HttpResponseFutureCallback(HttpUriRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public void addCallback(ListenableFutureCallback<? super ClientHttpResponse> callback) {
|
||||
this.callbacks.addCallback(callback);
|
||||
}
|
||||
|
||||
public void addSuccessCallback(SuccessCallback<? super ClientHttpResponse> callback) {
|
||||
this.callbacks.addSuccessCallback(callback);
|
||||
}
|
||||
|
||||
public void addFailureCallback(FailureCallback callback) {
|
||||
this.callbacks.addFailureCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(HttpResponse result) {
|
||||
this.callbacks.success(new HttpComponentsAsyncClientHttpResponse(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Exception ex) {
|
||||
this.callbacks.failure(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
this.request.abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class ClientHttpResponseFuture extends FutureAdapter<ClientHttpResponse, HttpResponse>
|
||||
implements ListenableFuture<ClientHttpResponse> {
|
||||
|
||||
private final HttpResponseFutureCallback callback;
|
||||
|
||||
public ClientHttpResponseFuture(Future<HttpResponse> response, HttpResponseFutureCallback callback) {
|
||||
super(response);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClientHttpResponse adapt(HttpResponse response) {
|
||||
return new HttpComponentsAsyncClientHttpResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(ListenableFutureCallback<? super ClientHttpResponse> callback) {
|
||||
this.callback.addCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(SuccessCallback<? super ClientHttpResponse> successCallback,
|
||||
FailureCallback failureCallback) {
|
||||
|
||||
this.callback.addSuccessCallback(successCallback);
|
||||
this.callback.addFailureCallback(failureCallback);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.Configurable;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClients;
|
||||
import org.apache.http.nio.client.HttpAsyncClient;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Asynchronous extension of the {@link HttpComponentsClientHttpRequestFactory}. Uses
|
||||
* <a href="https://hc.apache.org/httpcomponents-asyncclient-dev/">Apache HttpComponents
|
||||
* HttpAsyncClient 4.0</a> to create requests.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0
|
||||
* @see HttpAsyncClient
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.http.client.reactive.HttpComponentsClientHttpConnector}
|
||||
*/
|
||||
@Deprecated
|
||||
public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory
|
||||
implements AsyncClientHttpRequestFactory, InitializingBean {
|
||||
|
||||
private HttpAsyncClient asyncClient;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
|
||||
* with a default {@link HttpAsyncClient} and {@link HttpClient}.
|
||||
*/
|
||||
public HttpComponentsAsyncClientHttpRequestFactory() {
|
||||
super();
|
||||
this.asyncClient = HttpAsyncClients.createSystem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
|
||||
* with the given {@link HttpAsyncClient} instance and a default {@link HttpClient}.
|
||||
* @param asyncClient the HttpAsyncClient instance to use for this request factory
|
||||
* @since 4.3.10
|
||||
*/
|
||||
public HttpComponentsAsyncClientHttpRequestFactory(HttpAsyncClient asyncClient) {
|
||||
super();
|
||||
this.asyncClient = asyncClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
|
||||
* with the given {@link CloseableHttpAsyncClient} instance and a default {@link HttpClient}.
|
||||
* @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
|
||||
*/
|
||||
public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpAsyncClient asyncClient) {
|
||||
super();
|
||||
this.asyncClient = asyncClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
|
||||
* with the given {@link HttpClient} and {@link HttpAsyncClient} instances.
|
||||
* @param httpClient the HttpClient instance to use for this request factory
|
||||
* @param asyncClient the HttpAsyncClient instance to use for this request factory
|
||||
* @since 4.3.10
|
||||
*/
|
||||
public HttpComponentsAsyncClientHttpRequestFactory(HttpClient httpClient, HttpAsyncClient asyncClient) {
|
||||
super(httpClient);
|
||||
this.asyncClient = asyncClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
|
||||
* with the given {@link CloseableHttpClient} and {@link CloseableHttpAsyncClient} instances.
|
||||
* @param httpClient the CloseableHttpClient instance to use for this request factory
|
||||
* @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
|
||||
*/
|
||||
public HttpComponentsAsyncClientHttpRequestFactory(
|
||||
CloseableHttpClient httpClient, CloseableHttpAsyncClient asyncClient) {
|
||||
|
||||
super(httpClient);
|
||||
this.asyncClient = asyncClient;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the {@code HttpAsyncClient} used for
|
||||
* {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
|
||||
* @since 4.3.10
|
||||
* @see #setHttpClient(HttpClient)
|
||||
*/
|
||||
public void setAsyncClient(HttpAsyncClient asyncClient) {
|
||||
Assert.notNull(asyncClient, "HttpAsyncClient must not be null");
|
||||
this.asyncClient = asyncClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code HttpAsyncClient} used for
|
||||
* {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
|
||||
* @since 4.3.10
|
||||
* @see #getHttpClient()
|
||||
*/
|
||||
public HttpAsyncClient getAsyncClient() {
|
||||
return this.asyncClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code CloseableHttpAsyncClient} used for
|
||||
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
|
||||
* @deprecated as of 4.3.10, in favor of {@link #setAsyncClient(HttpAsyncClient)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setHttpAsyncClient(CloseableHttpAsyncClient asyncClient) {
|
||||
this.asyncClient = asyncClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code CloseableHttpAsyncClient} used for
|
||||
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
|
||||
* @deprecated as of 4.3.10, in favor of {@link #getAsyncClient()}
|
||||
*/
|
||||
@Deprecated
|
||||
public CloseableHttpAsyncClient getHttpAsyncClient() {
|
||||
Assert.state(this.asyncClient instanceof CloseableHttpAsyncClient,
|
||||
"No CloseableHttpAsyncClient - use getAsyncClient() instead");
|
||||
return (CloseableHttpAsyncClient) this.asyncClient;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
startAsyncClient();
|
||||
}
|
||||
|
||||
private HttpAsyncClient startAsyncClient() {
|
||||
HttpAsyncClient client = getAsyncClient();
|
||||
if (client instanceof CloseableHttpAsyncClient) {
|
||||
@SuppressWarnings("resource")
|
||||
CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) client;
|
||||
if (!closeableAsyncClient.isRunning()) {
|
||||
closeableAsyncClient.start();
|
||||
}
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
HttpAsyncClient client = startAsyncClient();
|
||||
|
||||
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
|
||||
postProcessHttpRequest(httpRequest);
|
||||
HttpContext context = createHttpContext(httpMethod, uri);
|
||||
if (context == null) {
|
||||
context = HttpClientContext.create();
|
||||
}
|
||||
|
||||
// Request configuration not set in the context
|
||||
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
|
||||
// Use request configuration given by the user, when available
|
||||
RequestConfig config = null;
|
||||
if (httpRequest instanceof Configurable) {
|
||||
config = ((Configurable) httpRequest).getConfig();
|
||||
}
|
||||
if (config == null) {
|
||||
config = createRequestConfig(client);
|
||||
}
|
||||
if (config != null) {
|
||||
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
|
||||
}
|
||||
}
|
||||
|
||||
return new HttpComponentsAsyncClientHttpRequest(client, httpRequest, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
try {
|
||||
super.destroy();
|
||||
}
|
||||
finally {
|
||||
HttpAsyncClient asyncClient = getAsyncClient();
|
||||
if (asyncClient instanceof Closeable) {
|
||||
((Closeable) asyncClient).close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpResponse} implementation based on
|
||||
* Apache HttpComponents HttpAsyncClient.
|
||||
*
|
||||
* <p>Created via the {@link HttpComponentsAsyncClientHttpRequest}.
|
||||
*
|
||||
* @author Oleg Kalnichevski
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @see HttpComponentsAsyncClientHttpRequest#executeAsync()
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.http.client.reactive.HttpComponentsClientHttpConnector}
|
||||
*/
|
||||
@Deprecated
|
||||
final class HttpComponentsAsyncClientHttpResponse extends AbstractClientHttpResponse {
|
||||
|
||||
private final HttpResponse httpResponse;
|
||||
|
||||
@Nullable
|
||||
private HttpHeaders headers;
|
||||
|
||||
|
||||
HttpComponentsAsyncClientHttpResponse(HttpResponse httpResponse) {
|
||||
this.httpResponse = httpResponse;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return this.httpResponse.getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() throws IOException {
|
||||
return this.httpResponse.getStatusLine().getReasonPhrase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
if (this.headers == null) {
|
||||
this.headers = new HttpHeaders();
|
||||
for (Header header : this.httpResponse.getAllHeaders()) {
|
||||
this.headers.add(header.getName(), header.getValue());
|
||||
}
|
||||
}
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
HttpEntity entity = this.httpResponse.getEntity();
|
||||
return (entity != null ? entity.getContent() : StreamUtils.emptyInput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// HTTP responses returned by async HTTP client are not bound to an
|
||||
// active connection and do not have to deallocate any resources...
|
||||
}
|
||||
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* An {@link AsyncClientHttpRequest} wrapper that enriches it proceeds the actual
|
||||
* request execution with calling the registered interceptors.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @author Rossen Stoyanchev
|
||||
* @see InterceptingAsyncClientHttpRequestFactory
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
class InterceptingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
|
||||
|
||||
private AsyncClientHttpRequestFactory requestFactory;
|
||||
|
||||
private List<AsyncClientHttpRequestInterceptor> interceptors;
|
||||
|
||||
private URI uri;
|
||||
|
||||
private HttpMethod httpMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Create new instance of {@link InterceptingAsyncClientHttpRequest}.
|
||||
* @param requestFactory the async request factory
|
||||
* @param interceptors the list of interceptors
|
||||
* @param uri the request URI
|
||||
* @param httpMethod the HTTP method
|
||||
*/
|
||||
public InterceptingAsyncClientHttpRequest(AsyncClientHttpRequestFactory requestFactory,
|
||||
List<AsyncClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod httpMethod) {
|
||||
|
||||
this.requestFactory = requestFactory;
|
||||
this.interceptors = interceptors;
|
||||
this.uri = uri;
|
||||
this.httpMethod = httpMethod;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers, byte[] body)
|
||||
throws IOException {
|
||||
|
||||
return new AsyncRequestExecution().executeAsync(this, body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return this.httpMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return this.httpMethod.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
|
||||
private class AsyncRequestExecution implements AsyncClientHttpRequestExecution {
|
||||
|
||||
private Iterator<AsyncClientHttpRequestInterceptor> iterator;
|
||||
|
||||
public AsyncRequestExecution() {
|
||||
this.iterator = interceptors.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<ClientHttpResponse> executeAsync(HttpRequest request, byte[] body)
|
||||
throws IOException {
|
||||
|
||||
if (this.iterator.hasNext()) {
|
||||
AsyncClientHttpRequestInterceptor interceptor = this.iterator.next();
|
||||
return interceptor.intercept(request, body, this);
|
||||
}
|
||||
else {
|
||||
URI uri = request.getURI();
|
||||
HttpMethod method = request.getMethod();
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
|
||||
Assert.state(method != null, "No standard HTTP method");
|
||||
AsyncClientHttpRequest delegate = requestFactory.createAsyncRequest(uri, method);
|
||||
delegate.getHeaders().putAll(headers);
|
||||
if (body.length > 0) {
|
||||
StreamUtils.copy(body, delegate.getBody());
|
||||
}
|
||||
|
||||
return delegate.executeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Wrapper for a {@link AsyncClientHttpRequestFactory} that has support for
|
||||
* {@link AsyncClientHttpRequestInterceptor AsyncClientHttpRequestInterceptors}.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @since 4.3
|
||||
* @see InterceptingAsyncClientHttpRequest
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public class InterceptingAsyncClientHttpRequestFactory implements AsyncClientHttpRequestFactory {
|
||||
|
||||
private AsyncClientHttpRequestFactory delegate;
|
||||
|
||||
private List<AsyncClientHttpRequestInterceptor> interceptors;
|
||||
|
||||
|
||||
/**
|
||||
* Create new instance of {@link InterceptingAsyncClientHttpRequestFactory}
|
||||
* with delegated request factory and list of interceptors.
|
||||
* @param delegate the request factory to delegate to
|
||||
* @param interceptors the list of interceptors to use
|
||||
*/
|
||||
public InterceptingAsyncClientHttpRequestFactory(AsyncClientHttpRequestFactory delegate,
|
||||
@Nullable List<AsyncClientHttpRequestInterceptor> interceptors) {
|
||||
|
||||
this.delegate = delegate;
|
||||
this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod method) {
|
||||
return new InterceptingAsyncClientHttpRequest(this.delegate, this.interceptors, uri, method);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequest} implementation based on Netty 4.
|
||||
*
|
||||
* <p>Created via the {@link Netty4ClientHttpRequestFactory}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @since 4.1.2
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector}
|
||||
*/
|
||||
@Deprecated
|
||||
class Netty4ClientHttpRequest extends AbstractAsyncClientHttpRequest implements ClientHttpRequest {
|
||||
|
||||
private final Bootstrap bootstrap;
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private final HttpMethod method;
|
||||
|
||||
private final ByteBufOutputStream body;
|
||||
|
||||
|
||||
public Netty4ClientHttpRequest(Bootstrap bootstrap, URI uri, HttpMethod method) {
|
||||
this.bootstrap = bootstrap;
|
||||
this.uri = uri;
|
||||
this.method = method;
|
||||
this.body = new ByteBufOutputStream(Unpooled.buffer(1024));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return this.method.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse execute() throws IOException {
|
||||
try {
|
||||
return executeAsync().get();
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException("Interrupted during request execution", ex);
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
if (ex.getCause() instanceof IOException) {
|
||||
throw (IOException) ex.getCause();
|
||||
}
|
||||
else {
|
||||
throw new IOException(ex.getMessage(), ex.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(final HttpHeaders headers) throws IOException {
|
||||
final SettableListenableFuture<ClientHttpResponse> responseFuture = new SettableListenableFuture<>();
|
||||
|
||||
ChannelFutureListener connectionListener = future -> {
|
||||
if (future.isSuccess()) {
|
||||
Channel channel = future.channel();
|
||||
channel.pipeline().addLast(new RequestExecuteHandler(responseFuture));
|
||||
FullHttpRequest nettyRequest = createFullHttpRequest(headers);
|
||||
channel.writeAndFlush(nettyRequest);
|
||||
}
|
||||
else {
|
||||
responseFuture.setException(future.cause());
|
||||
}
|
||||
};
|
||||
|
||||
this.bootstrap.connect(this.uri.getHost(), getPort(this.uri)).addListener(connectionListener);
|
||||
return responseFuture;
|
||||
}
|
||||
|
||||
private FullHttpRequest createFullHttpRequest(HttpHeaders headers) {
|
||||
io.netty.handler.codec.http.HttpMethod nettyMethod =
|
||||
io.netty.handler.codec.http.HttpMethod.valueOf(this.method.name());
|
||||
|
||||
String authority = this.uri.getRawAuthority();
|
||||
String path = this.uri.toString().substring(this.uri.toString().indexOf(authority) + authority.length());
|
||||
FullHttpRequest nettyRequest = new DefaultFullHttpRequest(
|
||||
HttpVersion.HTTP_1_1, nettyMethod, path, this.body.buffer());
|
||||
|
||||
nettyRequest.headers().set(HttpHeaders.HOST, this.uri.getHost() + ":" + getPort(this.uri));
|
||||
nettyRequest.headers().set(HttpHeaders.CONNECTION, "close");
|
||||
headers.forEach((headerName, headerValues) -> nettyRequest.headers().add(headerName, headerValues));
|
||||
if (!nettyRequest.headers().contains(HttpHeaders.CONTENT_LENGTH) && this.body.buffer().readableBytes() > 0) {
|
||||
nettyRequest.headers().set(HttpHeaders.CONTENT_LENGTH, this.body.buffer().readableBytes());
|
||||
}
|
||||
|
||||
return nettyRequest;
|
||||
}
|
||||
|
||||
private static int getPort(URI uri) {
|
||||
int port = uri.getPort();
|
||||
if (port == -1) {
|
||||
if ("http".equalsIgnoreCase(uri.getScheme())) {
|
||||
port = 80;
|
||||
}
|
||||
else if ("https".equalsIgnoreCase(uri.getScheme())) {
|
||||
port = 443;
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A SimpleChannelInboundHandler to update the given SettableListenableFuture.
|
||||
*/
|
||||
private static class RequestExecuteHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
|
||||
|
||||
private final SettableListenableFuture<ClientHttpResponse> responseFuture;
|
||||
|
||||
public RequestExecuteHandler(SettableListenableFuture<ClientHttpResponse> responseFuture) {
|
||||
this.responseFuture = responseFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext context, FullHttpResponse response) throws Exception {
|
||||
this.responseFuture.set(new Netty4ClientHttpResponse(context, response));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext context, Throwable cause) throws Exception {
|
||||
this.responseFuture.setException(cause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelConfig;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.SocketChannelConfig;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.http.HttpClientCodec;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.http.client.ClientHttpRequestFactory} implementation
|
||||
* that uses <a href="https://netty.io/">Netty 4</a> to create requests.
|
||||
*
|
||||
* <p>Allows to use a pre-configured {@link EventLoopGroup} instance: useful for
|
||||
* sharing across multiple clients.
|
||||
*
|
||||
* <p>Note that this implementation consistently closes the HTTP connection on each
|
||||
* request.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @author Mark Paluch
|
||||
* @since 4.1.2
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector}
|
||||
*/
|
||||
@Deprecated
|
||||
public class Netty4ClientHttpRequestFactory implements ClientHttpRequestFactory,
|
||||
AsyncClientHttpRequestFactory, InitializingBean, DisposableBean {
|
||||
|
||||
/**
|
||||
* The default maximum response size.
|
||||
* @see #setMaxResponseSize(int)
|
||||
*/
|
||||
public static final int DEFAULT_MAX_RESPONSE_SIZE = 1024 * 1024 * 10;
|
||||
|
||||
|
||||
private final EventLoopGroup eventLoopGroup;
|
||||
|
||||
private final boolean defaultEventLoopGroup;
|
||||
|
||||
private int maxResponseSize = DEFAULT_MAX_RESPONSE_SIZE;
|
||||
|
||||
@Nullable
|
||||
private SslContext sslContext;
|
||||
|
||||
private int connectTimeout = -1;
|
||||
|
||||
private int readTimeout = -1;
|
||||
|
||||
@Nullable
|
||||
private volatile Bootstrap bootstrap;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code Netty4ClientHttpRequestFactory} with a default
|
||||
* {@link NioEventLoopGroup}.
|
||||
*/
|
||||
public Netty4ClientHttpRequestFactory() {
|
||||
int ioWorkerCount = Runtime.getRuntime().availableProcessors() * 2;
|
||||
this.eventLoopGroup = new NioEventLoopGroup(ioWorkerCount);
|
||||
this.defaultEventLoopGroup = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code Netty4ClientHttpRequestFactory} with the given
|
||||
* {@link EventLoopGroup}.
|
||||
* <p><b>NOTE:</b> the given group will <strong>not</strong> be
|
||||
* {@linkplain EventLoopGroup#shutdownGracefully() shutdown} by this factory;
|
||||
* doing so becomes the responsibility of the caller.
|
||||
*/
|
||||
public Netty4ClientHttpRequestFactory(EventLoopGroup eventLoopGroup) {
|
||||
Assert.notNull(eventLoopGroup, "EventLoopGroup must not be null");
|
||||
this.eventLoopGroup = eventLoopGroup;
|
||||
this.defaultEventLoopGroup = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the default maximum response size.
|
||||
* <p>By default this is set to {@link #DEFAULT_MAX_RESPONSE_SIZE}.
|
||||
* @since 4.1.5
|
||||
* @see HttpObjectAggregator#HttpObjectAggregator(int)
|
||||
*/
|
||||
public void setMaxResponseSize(int maxResponseSize) {
|
||||
this.maxResponseSize = maxResponseSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SSL context. When configured it is used to create and insert an
|
||||
* {@link io.netty.handler.ssl.SslHandler} in the channel pipeline.
|
||||
* <p>A default client SslContext is configured if none has been provided.
|
||||
*/
|
||||
public void setSslContext(SslContext sslContext) {
|
||||
this.sslContext = sslContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying connect timeout (in milliseconds).
|
||||
* A timeout value of 0 specifies an infinite timeout.
|
||||
* @see ChannelConfig#setConnectTimeoutMillis(int)
|
||||
*/
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying URLConnection's read timeout (in milliseconds).
|
||||
* A timeout value of 0 specifies an infinite timeout.
|
||||
* @see ReadTimeoutHandler
|
||||
*/
|
||||
public void setReadTimeout(int readTimeout) {
|
||||
this.readTimeout = readTimeout;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (this.sslContext == null) {
|
||||
this.sslContext = getDefaultClientSslContext();
|
||||
}
|
||||
}
|
||||
|
||||
private SslContext getDefaultClientSslContext() {
|
||||
try {
|
||||
return SslContextBuilder.forClient().build();
|
||||
}
|
||||
catch (SSLException ex) {
|
||||
throw new IllegalStateException("Could not create default client SslContext", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
return createRequestInternal(uri, httpMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
return createRequestInternal(uri, httpMethod);
|
||||
}
|
||||
|
||||
private Netty4ClientHttpRequest createRequestInternal(URI uri, HttpMethod httpMethod) {
|
||||
return new Netty4ClientHttpRequest(getBootstrap(uri), uri, httpMethod);
|
||||
}
|
||||
|
||||
private Bootstrap getBootstrap(URI uri) {
|
||||
boolean isSecure = (uri.getPort() == 443 || "https".equalsIgnoreCase(uri.getScheme()));
|
||||
if (isSecure) {
|
||||
return buildBootstrap(uri, true);
|
||||
}
|
||||
else {
|
||||
Bootstrap bootstrap = this.bootstrap;
|
||||
if (bootstrap == null) {
|
||||
bootstrap = buildBootstrap(uri, false);
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
return bootstrap;
|
||||
}
|
||||
}
|
||||
|
||||
private Bootstrap buildBootstrap(URI uri, boolean isSecure) {
|
||||
Bootstrap bootstrap = new Bootstrap();
|
||||
bootstrap.group(this.eventLoopGroup).channel(NioSocketChannel.class)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel channel) throws Exception {
|
||||
configureChannel(channel.config());
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
if (isSecure) {
|
||||
Assert.notNull(sslContext, "sslContext should not be null");
|
||||
pipeline.addLast(sslContext.newHandler(channel.alloc(), uri.getHost(), uri.getPort()));
|
||||
}
|
||||
pipeline.addLast(new HttpClientCodec());
|
||||
pipeline.addLast(new HttpObjectAggregator(maxResponseSize));
|
||||
if (readTimeout > 0) {
|
||||
pipeline.addLast(new ReadTimeoutHandler(readTimeout,
|
||||
TimeUnit.MILLISECONDS));
|
||||
}
|
||||
}
|
||||
});
|
||||
return bootstrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for changing properties on the given {@link SocketChannelConfig}.
|
||||
* <p>The default implementation sets the connect timeout based on the set property.
|
||||
* @param config the channel configuration
|
||||
*/
|
||||
protected void configureChannel(SocketChannelConfig config) {
|
||||
if (this.connectTimeout >= 0) {
|
||||
config.setConnectTimeoutMillis(this.connectTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() throws InterruptedException {
|
||||
if (this.defaultEventLoopGroup) {
|
||||
// Clean up the EventLoopGroup if we created it in the constructor
|
||||
this.eventLoopGroup.shutdownGracefully().sync();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpResponse} implementation based on Netty 4.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.1.2
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector}
|
||||
*/
|
||||
@Deprecated
|
||||
class Netty4ClientHttpResponse extends AbstractClientHttpResponse {
|
||||
|
||||
private final ChannelHandlerContext context;
|
||||
|
||||
private final FullHttpResponse nettyResponse;
|
||||
|
||||
private final ByteBufInputStream body;
|
||||
|
||||
@Nullable
|
||||
private volatile HttpHeaders headers;
|
||||
|
||||
|
||||
public Netty4ClientHttpResponse(ChannelHandlerContext context, FullHttpResponse nettyResponse) {
|
||||
Assert.notNull(context, "ChannelHandlerContext must not be null");
|
||||
Assert.notNull(nettyResponse, "FullHttpResponse must not be null");
|
||||
this.context = context;
|
||||
this.nettyResponse = nettyResponse;
|
||||
this.body = new ByteBufInputStream(this.nettyResponse.content());
|
||||
this.nettyResponse.retain();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return this.nettyResponse.getStatus().code();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() throws IOException {
|
||||
return this.nettyResponse.getStatus().reasonPhrase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new HttpHeaders();
|
||||
for (Map.Entry<String, String> entry : this.nettyResponse.headers()) {
|
||||
headers.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.nettyResponse.release();
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
/**
|
||||
* {@link AsyncClientHttpRequest} implementation based on OkHttp 3.x.
|
||||
*
|
||||
* <p>Created via the {@link OkHttp3ClientHttpRequestFactory}.
|
||||
*
|
||||
* @author Luciano Leggieri
|
||||
* @author Arjen Poutsma
|
||||
* @author Roy Clarkson
|
||||
* @since 4.3
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
class OkHttp3AsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
|
||||
|
||||
private final OkHttpClient client;
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private final HttpMethod method;
|
||||
|
||||
|
||||
public OkHttp3AsyncClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method) {
|
||||
this.client = client;
|
||||
this.uri = uri;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return this.method.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers, byte[] content)
|
||||
throws IOException {
|
||||
|
||||
Request request = OkHttp3ClientHttpRequestFactory.buildRequest(headers, content, this.uri, this.method);
|
||||
return new OkHttpListenableFuture(this.client.newCall(request));
|
||||
}
|
||||
|
||||
|
||||
private static class OkHttpListenableFuture extends SettableListenableFuture<ClientHttpResponse> {
|
||||
|
||||
private final Call call;
|
||||
|
||||
public OkHttpListenableFuture(Call call) {
|
||||
this.call = call;
|
||||
this.call.enqueue(new Callback() {
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) {
|
||||
set(new OkHttp3ClientHttpResponse(response));
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Call call, IOException ex) {
|
||||
setException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void interruptTask() {
|
||||
this.call.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -42,9 +42,7 @@ import org.springframework.util.StringUtils;
|
|||
* @author Roy Clarkson
|
||||
* @since 4.3
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class OkHttp3ClientHttpRequestFactory
|
||||
implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory, DisposableBean {
|
||||
public class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {
|
||||
|
||||
private OkHttpClient client;
|
||||
|
||||
|
@ -106,11 +104,6 @@ public class OkHttp3ClientHttpRequestFactory
|
|||
return new OkHttp3ClientHttpRequest(this.client, uri, httpMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) {
|
||||
return new OkHttp3AsyncClientHttpRequest(this.client, uri, httpMethod);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() throws IOException {
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.http.client.ClientHttpRequest} implementation that uses
|
||||
* standard JDK facilities to execute buffered requests. Created via the
|
||||
* {@link org.springframework.http.client.SimpleClientHttpRequestFactory}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
* @see org.springframework.http.client.SimpleClientHttpRequestFactory#createRequest
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
final class SimpleBufferingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
|
||||
|
||||
private final HttpURLConnection connection;
|
||||
|
||||
private final boolean outputStreaming;
|
||||
|
||||
private final AsyncListenableTaskExecutor taskExecutor;
|
||||
|
||||
|
||||
SimpleBufferingAsyncClientHttpRequest(HttpURLConnection connection,
|
||||
boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
|
||||
|
||||
this.connection = connection;
|
||||
this.outputStreaming = outputStreaming;
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return this.connection.getRequestMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
try {
|
||||
return this.connection.getURL().toURI();
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Could not get HttpURLConnection URI: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(
|
||||
HttpHeaders headers, byte[] bufferedOutput) throws IOException {
|
||||
|
||||
return this.taskExecutor.submitListenable(() -> {
|
||||
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
|
||||
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE
|
||||
if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
|
||||
this.connection.setDoOutput(false);
|
||||
}
|
||||
if (this.connection.getDoOutput() && this.outputStreaming) {
|
||||
this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
|
||||
}
|
||||
this.connection.connect();
|
||||
if (this.connection.getDoOutput()) {
|
||||
FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
|
||||
}
|
||||
else {
|
||||
// Immediately trigger the request in a no-output scenario as well
|
||||
this.connection.getResponseCode();
|
||||
}
|
||||
return new SimpleClientHttpResponse(this.connection);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -23,10 +23,8 @@ import java.net.URI;
|
|||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequestFactory} implementation that uses standard JDK facilities.
|
||||
|
@ -37,8 +35,7 @@ import org.springframework.util.Assert;
|
|||
* @see java.net.HttpURLConnection
|
||||
* @see HttpComponentsClientHttpRequestFactory
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
|
||||
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory {
|
||||
|
||||
private static final int DEFAULT_CHUNK_SIZE = 4096;
|
||||
|
||||
|
@ -56,9 +53,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory,
|
|||
|
||||
private boolean outputStreaming = true;
|
||||
|
||||
@Nullable
|
||||
private AsyncListenableTaskExecutor taskExecutor;
|
||||
|
||||
|
||||
/**
|
||||
* Set the {@link Proxy} to use for this request factory.
|
||||
|
@ -130,15 +124,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory,
|
|||
this.outputStreaming = outputStreaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the task executor for this request factory. Setting this property is required
|
||||
* for {@linkplain #createAsyncRequest(URI, HttpMethod) creating asynchronous requests}.
|
||||
* @param taskExecutor the task executor
|
||||
*/
|
||||
public void setTaskExecutor(AsyncListenableTaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
|
@ -153,27 +138,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Setting the {@link #setTaskExecutor taskExecutor} property is required before calling this method.
|
||||
*/
|
||||
@Override
|
||||
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
Assert.state(this.taskExecutor != null, "Asynchronous execution requires TaskExecutor to be set");
|
||||
|
||||
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
|
||||
prepareConnection(connection, httpMethod.name());
|
||||
|
||||
if (this.bufferRequestBody) {
|
||||
return new SimpleBufferingAsyncClientHttpRequest(
|
||||
connection, this.outputStreaming, this.taskExecutor);
|
||||
}
|
||||
else {
|
||||
return new SimpleStreamingAsyncClientHttpRequest(
|
||||
connection, this.chunkSize, this.outputStreaming, this.taskExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens and returns a connection to the given URL.
|
||||
* <p>The default implementation uses the given {@linkplain #setProxy(java.net.Proxy) proxy} -
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.http.client.ClientHttpRequest} implementation
|
||||
* that uses standard Java facilities to execute streaming requests. Created
|
||||
* via the {@link org.springframework.http.client.SimpleClientHttpRequestFactory}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
* @see org.springframework.http.client.SimpleClientHttpRequestFactory#createRequest
|
||||
* @see org.springframework.http.client.support.AsyncHttpAccessor
|
||||
* @see org.springframework.web.client.AsyncRestTemplate
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
final class SimpleStreamingAsyncClientHttpRequest extends AbstractAsyncClientHttpRequest {
|
||||
|
||||
private final HttpURLConnection connection;
|
||||
|
||||
private final int chunkSize;
|
||||
|
||||
@Nullable
|
||||
private OutputStream body;
|
||||
|
||||
private final boolean outputStreaming;
|
||||
|
||||
private final AsyncListenableTaskExecutor taskExecutor;
|
||||
|
||||
|
||||
SimpleStreamingAsyncClientHttpRequest(HttpURLConnection connection, int chunkSize,
|
||||
boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
|
||||
|
||||
this.connection = connection;
|
||||
this.chunkSize = chunkSize;
|
||||
this.outputStreaming = outputStreaming;
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return this.connection.getRequestMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
try {
|
||||
return this.connection.getURL().toURI();
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Could not get HttpURLConnection URI: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
|
||||
if (this.body == null) {
|
||||
if (this.outputStreaming) {
|
||||
long contentLength = headers.getContentLength();
|
||||
if (contentLength >= 0) {
|
||||
this.connection.setFixedLengthStreamingMode(contentLength);
|
||||
}
|
||||
else {
|
||||
this.connection.setChunkedStreamingMode(this.chunkSize);
|
||||
}
|
||||
}
|
||||
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
|
||||
this.connection.connect();
|
||||
this.body = this.connection.getOutputStream();
|
||||
}
|
||||
return StreamUtils.nonClosing(this.body);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers) throws IOException {
|
||||
return this.taskExecutor.submitListenable(() -> {
|
||||
try {
|
||||
if (this.body != null) {
|
||||
this.body.close();
|
||||
}
|
||||
else {
|
||||
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
|
||||
this.connection.connect();
|
||||
// Immediately trigger the request in a no-output scenario as well
|
||||
this.connection.getResponseCode();
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
return new SimpleClientHttpResponse(this.connection);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import org.springframework.http.HttpLogging;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for {@link org.springframework.web.client.AsyncRestTemplate}
|
||||
* and other HTTP accessing gateway helpers, defining common properties
|
||||
* such as the {@link org.springframework.http.client.AsyncClientHttpRequestFactory}
|
||||
* to operate on.
|
||||
*
|
||||
* <p>Not intended to be used directly. See
|
||||
* {@link org.springframework.web.client.AsyncRestTemplate}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @see org.springframework.web.client.AsyncRestTemplate
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public class AsyncHttpAccessor {
|
||||
|
||||
/** Logger available to subclasses. */
|
||||
protected final Log logger = HttpLogging.forLogName(getClass());
|
||||
|
||||
@Nullable
|
||||
private org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the request factory that this accessor uses for obtaining {@link
|
||||
* org.springframework.http.client.ClientHttpRequest HttpRequests}.
|
||||
*/
|
||||
public void setAsyncRequestFactory(
|
||||
org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory) {
|
||||
|
||||
Assert.notNull(asyncRequestFactory, "AsyncClientHttpRequestFactory must not be null");
|
||||
this.asyncRequestFactory = asyncRequestFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the request factory that this accessor uses for obtaining {@link
|
||||
* org.springframework.http.client.ClientHttpRequest HttpRequests}.
|
||||
*/
|
||||
public org.springframework.http.client.AsyncClientHttpRequestFactory getAsyncRequestFactory() {
|
||||
Assert.state(this.asyncRequestFactory != null, "No AsyncClientHttpRequestFactory set");
|
||||
return this.asyncRequestFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link org.springframework.http.client.AsyncClientHttpRequest} via this template's
|
||||
* {@link org.springframework.http.client.AsyncClientHttpRequestFactory}.
|
||||
* @param url the URL to connect to
|
||||
* @param method the HTTP method to execute (GET, POST, etc.)
|
||||
* @return the created request
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
protected org.springframework.http.client.AsyncClientHttpRequest createAsyncRequest(URI url, HttpMethod method)
|
||||
throws IOException {
|
||||
|
||||
org.springframework.http.client.AsyncClientHttpRequest request =
|
||||
getAsyncRequestFactory().createAsyncRequest(url, method);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Created asynchronous " + method.name() + " request for \"" + url + "\"");
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* The HTTP accessor that extends the base {@link AsyncHttpAccessor} with
|
||||
* request intercepting functionality.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
* @deprecated as of Spring 5.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class InterceptingAsyncHttpAccessor extends AsyncHttpAccessor {
|
||||
|
||||
private List<org.springframework.http.client.AsyncClientHttpRequestInterceptor> interceptors =
|
||||
new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Set the request interceptors that this accessor should use.
|
||||
* @param interceptors the list of interceptors
|
||||
*/
|
||||
public void setInterceptors(List<org.springframework.http.client.AsyncClientHttpRequestInterceptor> interceptors) {
|
||||
this.interceptors = interceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the request interceptor that this accessor uses.
|
||||
*/
|
||||
public List<org.springframework.http.client.AsyncClientHttpRequestInterceptor> getInterceptors() {
|
||||
return this.interceptors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public org.springframework.http.client.AsyncClientHttpRequestFactory getAsyncRequestFactory() {
|
||||
org.springframework.http.client.AsyncClientHttpRequestFactory delegate = super.getAsyncRequestFactory();
|
||||
if (!CollectionUtils.isEmpty(getInterceptors())) {
|
||||
return new org.springframework.http.client.InterceptingAsyncClientHttpRequestFactory(delegate, getInterceptors());
|
||||
}
|
||||
else {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.web.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Callback interface for code that operates on an
|
||||
* {@link org.springframework.http.client.AsyncClientHttpRequest}. Allows to
|
||||
* manipulate the request headers, and write to the request body.
|
||||
*
|
||||
* <p>Used internally by the {@link AsyncRestTemplate}, but also useful for
|
||||
* application code.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @see org.springframework.web.client.AsyncRestTemplate#execute
|
||||
* @deprecated as of Spring 5.0, in favor of
|
||||
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction}
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@Deprecated
|
||||
public interface AsyncRequestCallback {
|
||||
|
||||
/**
|
||||
* Gets called by {@link AsyncRestTemplate#execute} with an opened {@code ClientHttpRequest}.
|
||||
* Does not need to care about closing the request or about handling errors:
|
||||
* this will all be handled by the {@code RestTemplate}.
|
||||
* @param request the active HTTP request
|
||||
* @throws java.io.IOException in case of I/O errors
|
||||
*/
|
||||
void doWithRequest(org.springframework.http.client.AsyncClientHttpRequest request) throws IOException;
|
||||
|
||||
}
|
|
@ -1,464 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.web.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of asynchronous RESTful operations.
|
||||
* Implemented by {@link AsyncRestTemplate}. Not often used directly, but a useful
|
||||
* option to enhance testability, as it can easily be mocked or stubbed.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @see AsyncRestTemplate
|
||||
* @see RestOperations
|
||||
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.web.reactive.function.client.WebClient}
|
||||
*/
|
||||
@Deprecated
|
||||
public interface AsyncRestOperations {
|
||||
|
||||
/**
|
||||
* Expose the synchronous Spring RestTemplate to allow synchronous invocation.
|
||||
*/
|
||||
RestOperations getRestOperations();
|
||||
|
||||
|
||||
// GET
|
||||
|
||||
/**
|
||||
* Asynchronously retrieve an entity by doing a GET on the specified URL.
|
||||
* The response is converted and stored in an {@link ResponseEntity}.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously retrieve a representation by doing a GET on the URI template.
|
||||
* The response is converted and stored in an {@link ResponseEntity}.
|
||||
* <p>URI Template variables are expanded using the given map.
|
||||
* @param url the URL
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the map containing variables for the URI template
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously retrieve a representation by doing a GET on the URL.
|
||||
* The response is converted and stored in an {@link ResponseEntity}.
|
||||
* @param url the URL
|
||||
* @param responseType the type of the return value
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> getForEntity(URI url, Class<T> responseType)
|
||||
throws RestClientException;
|
||||
|
||||
|
||||
// HEAD
|
||||
|
||||
/**
|
||||
* Asynchronously retrieve all headers of the resource specified by the URI template.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return all HTTP headers of that resource wrapped in a {@link Future}
|
||||
*/
|
||||
ListenableFuture<HttpHeaders> headForHeaders(String url, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously retrieve all headers of the resource specified by the URI template.
|
||||
* <p>URI Template variables are expanded using the given map.
|
||||
* @param url the URL
|
||||
* @param uriVariables the map containing variables for the URI template
|
||||
* @return all HTTP headers of that resource wrapped in a {@link Future}
|
||||
*/
|
||||
ListenableFuture<HttpHeaders> headForHeaders(String url, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously retrieve all headers of the resource specified by the URL.
|
||||
* @param url the URL
|
||||
* @return all HTTP headers of that resource wrapped in a {@link Future}
|
||||
*/
|
||||
ListenableFuture<HttpHeaders> headForHeaders(URI url) throws RestClientException;
|
||||
|
||||
|
||||
// POST
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing the given object to the URI template, and
|
||||
* asynchronously returns the value of the {@code Location} header. This header
|
||||
* typically indicates where the new resource is stored.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param request the Object to be POSTed (may be {@code null})
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the value for the {@code Location} header wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing the given object to the URI template, and
|
||||
* asynchronously returns the value of the {@code Location} header. This header
|
||||
* typically indicates where the new resource is stored.
|
||||
* <p>URI Template variables are expanded using the given map.
|
||||
* @param url the URL
|
||||
* @param request the Object to be POSTed (may be {@code null})
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the value for the {@code Location} header wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing the given object to the URL, and asynchronously
|
||||
* returns the value of the {@code Location} header. This header typically indicates
|
||||
* where the new resource is stored.
|
||||
* @param url the URL
|
||||
* @param request the Object to be POSTed (may be {@code null})
|
||||
* @return the value for the {@code Location} header wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
ListenableFuture<URI> postForLocation(URI url, @Nullable HttpEntity<?> request) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing the given object to the URI template,
|
||||
* and asynchronously returns the response as {@link ResponseEntity}.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param request the Object to be POSTed (may be {@code null})
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
|
||||
Class<T> responseType, Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing the given object to the URI template,
|
||||
* and asynchronously returns the response as {@link ResponseEntity}.
|
||||
* <p>URI Template variables are expanded using the given map.
|
||||
* @param url the URL
|
||||
* @param request the Object to be POSTed (may be {@code null})
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
|
||||
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing the given object to the URL,
|
||||
* and asynchronously returns the response as {@link ResponseEntity}.
|
||||
* @param url the URL
|
||||
* @param request the Object to be POSTed (may be {@code null})
|
||||
* @return the entity wrapped in a {@link Future}
|
||||
* @see org.springframework.http.HttpEntity
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> postForEntity(URI url, @Nullable HttpEntity<?> request,
|
||||
Class<T> responseType) throws RestClientException;
|
||||
|
||||
|
||||
// PUT
|
||||
|
||||
/**
|
||||
* Create or update a resource by PUTting the given object to the URI.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* <p>The Future will return a {@code null} result upon completion.
|
||||
* @param url the URL
|
||||
* @param request the Object to be PUT (may be {@code null})
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @see HttpEntity
|
||||
*/
|
||||
ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Creates a new resource by PUTting the given object to URI template.
|
||||
* <p>URI Template variables are expanded using the given map.
|
||||
* <p>The Future will return a {@code null} result upon completion.
|
||||
* @param url the URL
|
||||
* @param request the Object to be PUT (may be {@code null})
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @see HttpEntity
|
||||
*/
|
||||
ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Creates a new resource by PUTting the given object to URL.
|
||||
* <p>The Future will return a {@code null} result upon completion.
|
||||
* @param url the URL
|
||||
* @param request the Object to be PUT (may be {@code null})
|
||||
* @see HttpEntity
|
||||
*/
|
||||
ListenableFuture<?> put(URI url, @Nullable HttpEntity<?> request) throws RestClientException;
|
||||
|
||||
|
||||
// DELETE
|
||||
|
||||
/**
|
||||
* Asynchronously delete the resources at the specified URI.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* <p>The Future will return a {@code null} result upon completion.
|
||||
* @param url the URL
|
||||
* @param uriVariables the variables to expand in the template
|
||||
*/
|
||||
ListenableFuture<?> delete(String url, Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously delete the resources at the specified URI.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* <p>The Future will return a {@code null} result upon completion.
|
||||
* @param url the URL
|
||||
* @param uriVariables the variables to expand in the template
|
||||
*/
|
||||
ListenableFuture<?> delete(String url, Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously delete the resources at the specified URI.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* <p>The Future will return a {@code null} result upon completion.
|
||||
* @param url the URL
|
||||
*/
|
||||
ListenableFuture<?> delete(URI url) throws RestClientException;
|
||||
|
||||
|
||||
// OPTIONS
|
||||
|
||||
/**
|
||||
* Asynchronously return the value of the Allow header for the given URI.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the value of the allow header wrapped in a {@link Future}
|
||||
*/
|
||||
ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously return the value of the Allow header for the given URI.
|
||||
* <p>URI Template variables are expanded using the given map.
|
||||
* @param url the URL
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the value of the allow header wrapped in a {@link Future}
|
||||
*/
|
||||
ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously return the value of the Allow header for the given URL.
|
||||
* @param url the URL
|
||||
* @return the value of the allow header wrapped in a {@link Future}
|
||||
*/
|
||||
ListenableFuture<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException;
|
||||
|
||||
|
||||
// exchange
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, writing the
|
||||
* given request entity to the request, and returns the response as
|
||||
* {@link ResponseEntity}.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request
|
||||
* (may be {@code null})
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, writing the
|
||||
* given request entity to the request, and returns the response as
|
||||
* {@link ResponseEntity}.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request
|
||||
* (may be {@code null})
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, writing the
|
||||
* given request entity to the request, and returns the response as
|
||||
* {@link ResponseEntity}.
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request
|
||||
* (may be {@code null})
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, Class<T> responseType)
|
||||
throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, writing the given
|
||||
* request entity to the request, and returns the response as {@link ResponseEntity}.
|
||||
* The given {@link ParameterizedTypeReference} is used to pass generic type
|
||||
* information:
|
||||
* <pre class="code">
|
||||
* ParameterizedTypeReference<List<MyBean>> myBean =
|
||||
* new ParameterizedTypeReference<List<MyBean>>() {};
|
||||
*
|
||||
* ResponseEntity<List<MyBean>> response =
|
||||
* template.exchange("https://example.com",HttpMethod.GET, null, myBean);
|
||||
* </pre>
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestEntity the entity (headers and/or body) to write to the
|
||||
* request (may be {@code null})
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, writing the given
|
||||
* request entity to the request, and returns the response as {@link ResponseEntity}.
|
||||
* The given {@link ParameterizedTypeReference} is used to pass generic type
|
||||
* information:
|
||||
* <pre class="code">
|
||||
* ParameterizedTypeReference<List<MyBean>> myBean =
|
||||
* new ParameterizedTypeReference<List<MyBean>>() {};
|
||||
*
|
||||
* ResponseEntity<List<MyBean>> response =
|
||||
* template.exchange("https://example.com",HttpMethod.GET, null, myBean);
|
||||
* </pre>
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request
|
||||
* (may be {@code null})
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, writing the given
|
||||
* request entity to the request, and returns the response as {@link ResponseEntity}.
|
||||
* The given {@link ParameterizedTypeReference} is used to pass generic type
|
||||
* information:
|
||||
* <pre class="code">
|
||||
* ParameterizedTypeReference<List<MyBean>> myBean =
|
||||
* new ParameterizedTypeReference<List<MyBean>>() {};
|
||||
*
|
||||
* ResponseEntity<List<MyBean>> response =
|
||||
* template.exchange("https://example.com",HttpMethod.GET, null, myBean);
|
||||
* </pre>
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request
|
||||
* (may be {@code null})
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity wrapped in a {@link Future}
|
||||
*/
|
||||
<T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
|
||||
throws RestClientException;
|
||||
|
||||
|
||||
// general execution
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, preparing the
|
||||
* request with the {@link AsyncRequestCallback}, and reading the response with a
|
||||
* {@link ResponseExtractor}.
|
||||
* <p>URI Template variables are expanded using the given URI variables, if any.
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestCallback object that prepares the request
|
||||
* @param responseExtractor object that extracts the return value from the response
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
<T> ListenableFuture<T> execute(String url, HttpMethod method,
|
||||
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor,
|
||||
Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URI template, preparing the
|
||||
* request with the {@link AsyncRequestCallback}, and reading the response with a
|
||||
* {@link ResponseExtractor}.
|
||||
* <p>URI Template variables are expanded using the given URI variables map.
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestCallback object that prepares the request
|
||||
* @param responseExtractor object that extracts the return value from the response
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
<T> ListenableFuture<T> execute(String url, HttpMethod method,
|
||||
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor,
|
||||
Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
* Asynchronously execute the HTTP method to the given URL, preparing the request
|
||||
* with the {@link AsyncRequestCallback}, and reading the response with a
|
||||
* {@link ResponseExtractor}.
|
||||
* @param url the URL
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestCallback object that prepares the request
|
||||
* @param responseExtractor object that extracts the return value from the response
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
<T> ListenableFuture<T> execute(URI url, HttpMethod method,
|
||||
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor)
|
||||
throws RestClientException;
|
||||
|
||||
}
|
|
@ -1,714 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.web.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureAdapter;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
import org.springframework.web.util.UriTemplateHandler;
|
||||
|
||||
/**
|
||||
* <strong>Spring's central class for asynchronous client-side HTTP access.</strong>
|
||||
* Exposes similar methods as {@link RestTemplate}, but returns {@link ListenableFuture}
|
||||
* wrappers as opposed to concrete results.
|
||||
*
|
||||
* <p>The {@code AsyncRestTemplate} exposes a synchronous {@link RestTemplate} via the
|
||||
* {@link #getRestOperations()} method and shares its {@linkplain #setErrorHandler error handler}
|
||||
* and {@linkplain #setMessageConverters message converters} with that {@code RestTemplate}.
|
||||
*
|
||||
* <p><strong>Note:</strong> by default {@code AsyncRestTemplate} relies on
|
||||
* standard JDK facilities to establish HTTP connections. You can switch to use
|
||||
* a different HTTP library such as Apache HttpComponents, Netty, and OkHttp by
|
||||
* using a constructor accepting an {@link org.springframework.http.client.AsyncClientHttpRequestFactory}.
|
||||
*
|
||||
* <p>For more information, please refer to the {@link RestTemplate} API documentation.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @see RestTemplate
|
||||
* @deprecated as of Spring 5.0, in favor of {@link org.springframework.web.reactive.function.client.WebClient}
|
||||
*/
|
||||
@Deprecated
|
||||
public class AsyncRestTemplate extends org.springframework.http.client.support.InterceptingAsyncHttpAccessor
|
||||
implements AsyncRestOperations {
|
||||
|
||||
private final RestTemplate syncTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code AsyncRestTemplate} using default settings.
|
||||
* <p>This constructor uses a {@link SimpleClientHttpRequestFactory} in combination
|
||||
* with a {@link SimpleAsyncTaskExecutor} for asynchronous execution.
|
||||
*/
|
||||
public AsyncRestTemplate() {
|
||||
this(new SimpleAsyncTaskExecutor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code AsyncRestTemplate} using the given
|
||||
* {@link AsyncTaskExecutor}.
|
||||
* <p>This constructor uses a {@link SimpleClientHttpRequestFactory} in combination
|
||||
* with the given {@code AsyncTaskExecutor} for asynchronous execution.
|
||||
*/
|
||||
public AsyncRestTemplate(AsyncListenableTaskExecutor taskExecutor) {
|
||||
Assert.notNull(taskExecutor, "AsyncTaskExecutor must not be null");
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
requestFactory.setTaskExecutor(taskExecutor);
|
||||
this.syncTemplate = new RestTemplate(requestFactory);
|
||||
setAsyncRequestFactory(requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code AsyncRestTemplate} using the given
|
||||
* {@link org.springframework.http.client.AsyncClientHttpRequestFactory}.
|
||||
* <p>This constructor will cast the given asynchronous
|
||||
* {@code AsyncClientHttpRequestFactory} to a {@link ClientHttpRequestFactory}. Since
|
||||
* all implementations of {@code ClientHttpRequestFactory} provided in Spring also
|
||||
* implement {@code AsyncClientHttpRequestFactory}, this should not result in a
|
||||
* {@code ClassCastException}.
|
||||
*/
|
||||
public AsyncRestTemplate(org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory) {
|
||||
this(asyncRequestFactory, (ClientHttpRequestFactory) asyncRequestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@code AsyncRestTemplate} using the given
|
||||
* asynchronous and synchronous request factories.
|
||||
* @param asyncRequestFactory the asynchronous request factory
|
||||
* @param syncRequestFactory the synchronous request factory
|
||||
*/
|
||||
public AsyncRestTemplate(org.springframework.http.client.AsyncClientHttpRequestFactory asyncRequestFactory,
|
||||
ClientHttpRequestFactory syncRequestFactory) {
|
||||
|
||||
this(asyncRequestFactory, new RestTemplate(syncRequestFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code AsyncRestTemplate} using the given
|
||||
* {@link org.springframework.http.client.AsyncClientHttpRequestFactory} and synchronous {@link RestTemplate}.
|
||||
* @param requestFactory the asynchronous request factory to use
|
||||
* @param restTemplate the synchronous template to use
|
||||
*/
|
||||
public AsyncRestTemplate(org.springframework.http.client.AsyncClientHttpRequestFactory requestFactory,
|
||||
RestTemplate restTemplate) {
|
||||
|
||||
Assert.notNull(restTemplate, "RestTemplate must not be null");
|
||||
this.syncTemplate = restTemplate;
|
||||
setAsyncRequestFactory(requestFactory);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the error handler.
|
||||
* <p>By default, AsyncRestTemplate uses a
|
||||
* {@link org.springframework.web.client.DefaultResponseErrorHandler}.
|
||||
*/
|
||||
public void setErrorHandler(ResponseErrorHandler errorHandler) {
|
||||
this.syncTemplate.setErrorHandler(errorHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the error handler.
|
||||
*/
|
||||
public ResponseErrorHandler getErrorHandler() {
|
||||
return this.syncTemplate.getErrorHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure default URI variable values. This is a shortcut for:
|
||||
* <pre class="code">
|
||||
* DefaultUriTemplateHandler handler = new DefaultUriTemplateHandler();
|
||||
* handler.setDefaultUriVariables(...);
|
||||
*
|
||||
* AsyncRestTemplate restTemplate = new AsyncRestTemplate();
|
||||
* restTemplate.setUriTemplateHandler(handler);
|
||||
* </pre>
|
||||
* @param defaultUriVariables the default URI variable values
|
||||
* @since 4.3
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void setDefaultUriVariables(Map<String, ?> defaultUriVariables) {
|
||||
UriTemplateHandler handler = this.syncTemplate.getUriTemplateHandler();
|
||||
if (handler instanceof DefaultUriBuilderFactory) {
|
||||
((DefaultUriBuilderFactory) handler).setDefaultUriVariables(defaultUriVariables);
|
||||
}
|
||||
else if (handler instanceof org.springframework.web.util.AbstractUriTemplateHandler) {
|
||||
((org.springframework.web.util.AbstractUriTemplateHandler) handler)
|
||||
.setDefaultUriVariables(defaultUriVariables);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"This property is not supported with the configured UriTemplateHandler.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This property has the same purpose as the corresponding property on the
|
||||
* {@code RestTemplate}. For more details see
|
||||
* {@link RestTemplate#setUriTemplateHandler}.
|
||||
* @param handler the URI template handler to use
|
||||
*/
|
||||
public void setUriTemplateHandler(UriTemplateHandler handler) {
|
||||
this.syncTemplate.setUriTemplateHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured URI template handler.
|
||||
*/
|
||||
public UriTemplateHandler getUriTemplateHandler() {
|
||||
return this.syncTemplate.getUriTemplateHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestOperations getRestOperations() {
|
||||
return this.syncTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message body converters to use.
|
||||
* <p>These converters are used to convert from and to HTTP requests and responses.
|
||||
*/
|
||||
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
|
||||
this.syncTemplate.setMessageConverters(messageConverters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message body converters.
|
||||
*/
|
||||
public List<HttpMessageConverter<?>> getMessageConverters() {
|
||||
return this.syncTemplate.getMessageConverters();
|
||||
}
|
||||
|
||||
|
||||
// GET
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType, Object... uriVariables)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(String url, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> getForEntity(URI url, Class<T> responseType)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
|
||||
// HEAD
|
||||
|
||||
@Override
|
||||
public ListenableFuture<HttpHeaders> headForHeaders(String url, Object... uriVariables)
|
||||
throws RestClientException {
|
||||
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<HttpHeaders> headForHeaders(String url, Map<String, ?> uriVariables)
|
||||
throws RestClientException {
|
||||
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<HttpHeaders> headForHeaders(URI url) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor);
|
||||
}
|
||||
|
||||
|
||||
// POST
|
||||
|
||||
@Override
|
||||
public ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Object... uriVars)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback callback = httpEntityCallback(request);
|
||||
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
|
||||
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.POST, callback, extractor, uriVars);
|
||||
return adaptToLocationHeader(future);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<URI> postForLocation(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVars)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback callback = httpEntityCallback(request);
|
||||
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
|
||||
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.POST, callback, extractor, uriVars);
|
||||
return adaptToLocationHeader(future);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<URI> postForLocation(URI url, @Nullable HttpEntity<?> request)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback callback = httpEntityCallback(request);
|
||||
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
|
||||
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.POST, callback, extractor);
|
||||
return adaptToLocationHeader(future);
|
||||
}
|
||||
|
||||
private static ListenableFuture<URI> adaptToLocationHeader(ListenableFuture<HttpHeaders> future) {
|
||||
return new ListenableFutureAdapter<URI, HttpHeaders>(future) {
|
||||
@Override
|
||||
@Nullable
|
||||
protected URI adapt(HttpHeaders headers) throws ExecutionException {
|
||||
return headers.getLocation();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
|
||||
Class<T> responseType, Object... uriVariables) throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(String url, @Nullable HttpEntity<?> request,
|
||||
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> postForEntity(URI url,
|
||||
@Nullable HttpEntity<?> request, Class<T> responseType) throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
|
||||
// PUT
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Object... uriVars)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
return execute(url, HttpMethod.PUT, requestCallback, null, uriVars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> put(String url, @Nullable HttpEntity<?> request, Map<String, ?> uriVars)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
return execute(url, HttpMethod.PUT, requestCallback, null, uriVars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> put(URI url, @Nullable HttpEntity<?> request) throws RestClientException {
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(request);
|
||||
return execute(url, HttpMethod.PUT, requestCallback, null);
|
||||
}
|
||||
|
||||
|
||||
// DELETE
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> delete(String url, Object... uriVariables) throws RestClientException {
|
||||
return execute(url, HttpMethod.DELETE, null, null, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> delete(String url, Map<String, ?> uriVariables) throws RestClientException {
|
||||
return execute(url, HttpMethod.DELETE, null, null, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> delete(URI url) throws RestClientException {
|
||||
return execute(url, HttpMethod.DELETE, null, null);
|
||||
}
|
||||
|
||||
|
||||
// OPTIONS
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Object... uriVars)
|
||||
throws RestClientException {
|
||||
|
||||
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
|
||||
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.OPTIONS, null, extractor, uriVars);
|
||||
return adaptToAllowHeader(future);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Set<HttpMethod>> optionsForAllow(String url, Map<String, ?> uriVars)
|
||||
throws RestClientException {
|
||||
|
||||
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
|
||||
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.OPTIONS, null, extractor, uriVars);
|
||||
return adaptToAllowHeader(future);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Set<HttpMethod>> optionsForAllow(URI url) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> extractor = headersExtractor();
|
||||
ListenableFuture<HttpHeaders> future = execute(url, HttpMethod.OPTIONS, null, extractor);
|
||||
return adaptToAllowHeader(future);
|
||||
}
|
||||
|
||||
private static ListenableFuture<Set<HttpMethod>> adaptToAllowHeader(ListenableFuture<HttpHeaders> future) {
|
||||
return new ListenableFutureAdapter<Set<HttpMethod>, HttpHeaders>(future) {
|
||||
@Override
|
||||
protected Set<HttpMethod> adapt(HttpHeaders headers) throws ExecutionException {
|
||||
return headers.getAllow();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// exchange
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables)
|
||||
throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, Class<T> responseType) throws RestClientException {
|
||||
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, method, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Object... uriVariables) throws RestClientException {
|
||||
|
||||
Type type = responseType.getType();
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, type);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(String url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
|
||||
Type type = responseType.getType();
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, type);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<ResponseEntity<T>> exchange(URI url, HttpMethod method,
|
||||
@Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
|
||||
throws RestClientException {
|
||||
|
||||
Type type = responseType.getType();
|
||||
AsyncRequestCallback requestCallback = httpEntityCallback(requestEntity, type);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
|
||||
return execute(url, method, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
|
||||
// general execution
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<T> execute(String url, HttpMethod method, @Nullable AsyncRequestCallback requestCallback,
|
||||
@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
|
||||
|
||||
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
|
||||
return doExecute(expanded, method, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<T> execute(String url, HttpMethod method,
|
||||
@Nullable AsyncRequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
|
||||
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
|
||||
return doExecute(expanded, method, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<T> execute(URI url, HttpMethod method,
|
||||
@Nullable AsyncRequestCallback requestCallback,
|
||||
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
|
||||
|
||||
return doExecute(url, method, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given method on the provided URI. The
|
||||
* {@link org.springframework.http.client.ClientHttpRequest}
|
||||
* is processed using the {@link RequestCallback}; the response with
|
||||
* the {@link ResponseExtractor}.
|
||||
* @param url the fully-expanded URL to connect to
|
||||
* @param method the HTTP method to execute (GET, POST, etc.)
|
||||
* @param requestCallback object that prepares the request (can be {@code null})
|
||||
* @param responseExtractor object that extracts the return value from the response (can
|
||||
* be {@code null})
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
protected <T> ListenableFuture<T> doExecute(URI url, HttpMethod method,
|
||||
@Nullable AsyncRequestCallback requestCallback,
|
||||
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
|
||||
|
||||
Assert.notNull(url, "'url' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
try {
|
||||
org.springframework.http.client.AsyncClientHttpRequest request = createAsyncRequest(url, method);
|
||||
if (requestCallback != null) {
|
||||
requestCallback.doWithRequest(request);
|
||||
}
|
||||
ListenableFuture<ClientHttpResponse> responseFuture = request.executeAsync();
|
||||
return new ResponseExtractorFuture<>(method, url, responseFuture, responseExtractor);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new ResourceAccessException("I/O error on " + method.name() +
|
||||
" request for \"" + url + "\":" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void logResponseStatus(HttpMethod method, URI url, ClientHttpResponse response) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
try {
|
||||
logger.debug("Async " + method.name() + " request for \"" + url + "\" resulted in " +
|
||||
response.getRawStatusCode() + " (" + response.getStatusText() + ")");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleResponseError(HttpMethod method, URI url, ClientHttpResponse response) throws IOException {
|
||||
if (logger.isWarnEnabled()) {
|
||||
try {
|
||||
logger.warn("Async " + method.name() + " request for \"" + url + "\" resulted in " +
|
||||
response.getRawStatusCode() + " (" + response.getStatusText() + "); invoking error handler");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
getErrorHandler().handleError(url, method, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request callback implementation that prepares the request {@code Accept}
|
||||
* headers based on the given response type and configured {@linkplain
|
||||
* #getMessageConverters() message converters}.
|
||||
*/
|
||||
protected <T> AsyncRequestCallback acceptHeaderRequestCallback(Class<T> responseType) {
|
||||
return new AsyncRequestCallbackAdapter(this.syncTemplate.acceptHeaderRequestCallback(responseType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request callback implementation that writes the given object to the
|
||||
* request stream.
|
||||
*/
|
||||
protected <T> AsyncRequestCallback httpEntityCallback(@Nullable HttpEntity<T> requestBody) {
|
||||
return new AsyncRequestCallbackAdapter(this.syncTemplate.httpEntityCallback(requestBody));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request callback implementation that writes the given object to the
|
||||
* request stream.
|
||||
*/
|
||||
protected <T> AsyncRequestCallback httpEntityCallback(@Nullable HttpEntity<T> request, Type responseType) {
|
||||
return new AsyncRequestCallbackAdapter(this.syncTemplate.httpEntityCallback(request, responseType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a response extractor for {@link ResponseEntity}.
|
||||
*/
|
||||
protected <T> ResponseExtractor<ResponseEntity<T>> responseEntityExtractor(Type responseType) {
|
||||
return this.syncTemplate.responseEntityExtractor(responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a response extractor for {@link HttpHeaders}.
|
||||
*/
|
||||
protected ResponseExtractor<HttpHeaders> headersExtractor() {
|
||||
return this.syncTemplate.headersExtractor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Future returned from
|
||||
* {@link #doExecute(URI, HttpMethod, AsyncRequestCallback, ResponseExtractor)}.
|
||||
*/
|
||||
private class ResponseExtractorFuture<T> extends ListenableFutureAdapter<T, ClientHttpResponse> {
|
||||
|
||||
private final HttpMethod method;
|
||||
|
||||
private final URI url;
|
||||
|
||||
@Nullable
|
||||
private final ResponseExtractor<T> responseExtractor;
|
||||
|
||||
public ResponseExtractorFuture(HttpMethod method, URI url,
|
||||
ListenableFuture<ClientHttpResponse> clientHttpResponseFuture,
|
||||
@Nullable ResponseExtractor<T> responseExtractor) {
|
||||
|
||||
super(clientHttpResponseFuture);
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
this.responseExtractor = responseExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected final T adapt(ClientHttpResponse response) throws ExecutionException {
|
||||
try {
|
||||
if (!getErrorHandler().hasError(response)) {
|
||||
logResponseStatus(this.method, this.url, response);
|
||||
}
|
||||
else {
|
||||
handleResponseError(this.method, this.url, response);
|
||||
}
|
||||
return convertResponse(response);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new ExecutionException(ex);
|
||||
}
|
||||
finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected T convertResponse(ClientHttpResponse response) throws IOException {
|
||||
return (this.responseExtractor != null ? this.responseExtractor.extractData(response) : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapts a {@link RequestCallback} to the {@link AsyncRequestCallback} interface.
|
||||
*/
|
||||
private static class AsyncRequestCallbackAdapter implements AsyncRequestCallback {
|
||||
|
||||
private final RequestCallback adaptee;
|
||||
|
||||
/**
|
||||
* Create a new {@code AsyncRequestCallbackAdapter} from the given
|
||||
* {@link RequestCallback}.
|
||||
* @param requestCallback the callback to base this adapter on
|
||||
*/
|
||||
public AsyncRequestCallbackAdapter(RequestCallback requestCallback) {
|
||||
this.adaptee = requestCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWithRequest(final org.springframework.http.client.AsyncClientHttpRequest request)
|
||||
throws IOException {
|
||||
|
||||
this.adaptee.doWithRequest(new ClientHttpRequest() {
|
||||
@Override
|
||||
public ClientHttpResponse execute() throws IOException {
|
||||
throw new UnsupportedOperationException("execute not supported");
|
||||
}
|
||||
@Override
|
||||
public OutputStream getBody() throws IOException {
|
||||
return request.getBody();
|
||||
}
|
||||
@Override
|
||||
@Nullable
|
||||
public HttpMethod getMethod() {
|
||||
return request.getMethod();
|
||||
}
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return request.getMethodValue();
|
||||
}
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return request.getURI();
|
||||
}
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return request.getHeaders();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.StreamingHttpOutputMessage;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class AbstractAsyncHttpRequestFactoryTests extends AbstractMockWebServerTests {
|
||||
|
||||
protected AsyncClientHttpRequestFactory factory;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public final void createFactory() throws Exception {
|
||||
this.factory = createRequestFactory();
|
||||
if (this.factory instanceof InitializingBean) {
|
||||
((InitializingBean) this.factory).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public final void destroyFactory() throws Exception {
|
||||
if (this.factory instanceof DisposableBean) {
|
||||
((DisposableBean) this.factory).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract AsyncClientHttpRequestFactory createRequestFactory();
|
||||
|
||||
|
||||
@Test
|
||||
public void status() throws Exception {
|
||||
URI uri = new URI(baseUrl + "/status/notfound");
|
||||
AsyncClientHttpRequest request = this.factory.createAsyncRequest(uri, HttpMethod.GET);
|
||||
assertThat(request.getMethod()).as("Invalid HTTP method").isEqualTo(HttpMethod.GET);
|
||||
assertThat(request.getURI()).as("Invalid HTTP URI").isEqualTo(uri);
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
try (ClientHttpResponse response = futureResponse.get()) {
|
||||
assertThat(response.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statusCallback() throws Exception {
|
||||
URI uri = new URI(baseUrl + "/status/notfound");
|
||||
AsyncClientHttpRequest request = this.factory.createAsyncRequest(uri, HttpMethod.GET);
|
||||
assertThat(request.getMethod()).as("Invalid HTTP method").isEqualTo(HttpMethod.GET);
|
||||
assertThat(request.getURI()).as("Invalid HTTP URI").isEqualTo(uri);
|
||||
ListenableFuture<ClientHttpResponse> listenableFuture = request.executeAsync();
|
||||
listenableFuture.addCallback(new ListenableFutureCallback<ClientHttpResponse>() {
|
||||
@Override
|
||||
public void onSuccess(ClientHttpResponse result) {
|
||||
try {
|
||||
assertThat(result.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new AssertionError(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
throw new AssertionError(ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
try (ClientHttpResponse response = listenableFuture.get()) {
|
||||
assertThat(response.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void echo() throws Exception {
|
||||
AsyncClientHttpRequest request = this.factory.createAsyncRequest(new URI(baseUrl + "/echo"), HttpMethod.PUT);
|
||||
assertThat(request.getMethod()).as("Invalid HTTP method").isEqualTo(HttpMethod.PUT);
|
||||
String headerName = "MyHeader";
|
||||
String headerValue1 = "value1";
|
||||
request.getHeaders().add(headerName, headerValue1);
|
||||
String headerValue2 = "value2";
|
||||
request.getHeaders().add(headerName, headerValue2);
|
||||
final byte[] body = "Hello World".getBytes("UTF-8");
|
||||
request.getHeaders().setContentLength(body.length);
|
||||
|
||||
if (request instanceof StreamingHttpOutputMessage) {
|
||||
StreamingHttpOutputMessage streamingRequest = (StreamingHttpOutputMessage) request;
|
||||
streamingRequest.setBody(outputStream -> StreamUtils.copy(body, outputStream));
|
||||
}
|
||||
else {
|
||||
StreamUtils.copy(body, request.getBody());
|
||||
}
|
||||
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
try ( ClientHttpResponse response = futureResponse.get()) {
|
||||
assertThat(response.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getHeaders().containsKey(headerName)).as("Header not found").isTrue();
|
||||
assertThat(response.getHeaders().get(headerName)).as("Header value not found").isEqualTo(Arrays.asList(headerValue1, headerValue2));
|
||||
byte[] result = FileCopyUtils.copyToByteArray(response.getBody());
|
||||
assertThat(Arrays.equals(body, result)).as("Invalid body").isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleWrites() throws Exception {
|
||||
AsyncClientHttpRequest request = this.factory.createAsyncRequest(new URI(baseUrl + "/echo"), HttpMethod.POST);
|
||||
final byte[] body = "Hello World".getBytes("UTF-8");
|
||||
|
||||
if (request instanceof StreamingHttpOutputMessage) {
|
||||
StreamingHttpOutputMessage streamingRequest = (StreamingHttpOutputMessage) request;
|
||||
streamingRequest.setBody(outputStream -> StreamUtils.copy(body, outputStream));
|
||||
}
|
||||
else {
|
||||
StreamUtils.copy(body, request.getBody());
|
||||
}
|
||||
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
try (ClientHttpResponse response = futureResponse.get()) {
|
||||
assertThat(response).isNotNull();
|
||||
assertThatIllegalStateException().isThrownBy(() -> FileCopyUtils.copy(body, request.getBody()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersAfterExecute() throws Exception {
|
||||
AsyncClientHttpRequest request = this.factory.createAsyncRequest(new URI(baseUrl + "/echo"), HttpMethod.POST);
|
||||
request.getHeaders().add("MyHeader", "value");
|
||||
byte[] body = "Hello World".getBytes("UTF-8");
|
||||
FileCopyUtils.copy(body, request.getBody());
|
||||
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
try (ClientHttpResponse response = futureResponse.get()) {
|
||||
assertThat(response).isNotNull();
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
||||
request.getHeaders().add("MyHeader", "value"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
assertHttpMethod("get", HttpMethod.GET);
|
||||
assertHttpMethod("head", HttpMethod.HEAD);
|
||||
assertHttpMethod("post", HttpMethod.POST);
|
||||
assertHttpMethod("put", HttpMethod.PUT);
|
||||
assertHttpMethod("options", HttpMethod.OPTIONS);
|
||||
assertHttpMethod("delete", HttpMethod.DELETE);
|
||||
}
|
||||
|
||||
protected void assertHttpMethod(String path, HttpMethod method) throws Exception {
|
||||
AsyncClientHttpRequest request = this.factory.createAsyncRequest(new URI(baseUrl + "/methods/" + path), method);
|
||||
if (method == HttpMethod.POST || method == HttpMethod.PUT || method == HttpMethod.PATCH) {
|
||||
// requires a body
|
||||
request.getBody().write(32);
|
||||
}
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
try (ClientHttpResponse response = futureResponse.get()) {
|
||||
assertThat(response.getStatusCode()).as("Invalid response status").isEqualTo(HttpStatus.OK);
|
||||
assertThat(request.getMethod().name()).as("Invalid method").isEqualTo(path.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancel() throws Exception {
|
||||
URI uri = new URI(baseUrl + "/status/notfound");
|
||||
AsyncClientHttpRequest request = this.factory.createAsyncRequest(uri, HttpMethod.GET);
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
futureResponse.cancel(true);
|
||||
assertThat(futureResponse.isCancelled()).isTrue();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.net.ProtocolException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
public class BufferedSimpleAsyncHttpRequestFactoryTests extends AbstractAsyncHttpRequestFactoryTests {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected AsyncClientHttpRequestFactory createRequestFactory() {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
AsyncListenableTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
|
||||
requestFactory.setTaskExecutor(taskExecutor);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
super.httpMethods();
|
||||
try {
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
catch (ProtocolException ex) {
|
||||
// Currently HttpURLConnection does not support HTTP PATCH
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class HttpComponentsAsyncClientHttpRequestFactoryTests extends AbstractAsyncHttpRequestFactoryTests {
|
||||
|
||||
@Override
|
||||
protected AsyncClientHttpRequestFactory createRequestFactory() {
|
||||
return new HttpComponentsAsyncClientHttpRequestFactory();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
super.httpMethods();
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customHttpAsyncClientUsesItsDefault() throws Exception {
|
||||
HttpComponentsAsyncClientHttpRequestFactory factory =
|
||||
new HttpComponentsAsyncClientHttpRequestFactory();
|
||||
|
||||
URI uri = new URI(baseUrl + "/status/ok");
|
||||
HttpComponentsAsyncClientHttpRequest request = (HttpComponentsAsyncClientHttpRequest)
|
||||
factory.createAsyncRequest(uri, HttpMethod.GET);
|
||||
|
||||
assertThat(request.getHttpContext().getAttribute(HttpClientContext.REQUEST_CONFIG)).as("No custom config should be set with a custom HttpAsyncClient").isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultSettingsOfHttpAsyncClientLostOnExecutorCustomization() throws Exception {
|
||||
CloseableHttpAsyncClient client = HttpAsyncClientBuilder.create()
|
||||
.setDefaultRequestConfig(RequestConfig.custom().setConnectTimeout(1234).build())
|
||||
.build();
|
||||
HttpComponentsAsyncClientHttpRequestFactory factory = new HttpComponentsAsyncClientHttpRequestFactory(client);
|
||||
|
||||
URI uri = new URI(baseUrl + "/status/ok");
|
||||
HttpComponentsAsyncClientHttpRequest request = (HttpComponentsAsyncClientHttpRequest)
|
||||
factory.createAsyncRequest(uri, HttpMethod.GET);
|
||||
|
||||
assertThat(request.getHttpContext().getAttribute(HttpClientContext.REQUEST_CONFIG)).as("No custom config should be set with a custom HttpClient").isNull();
|
||||
|
||||
factory.setConnectionRequestTimeout(4567);
|
||||
HttpComponentsAsyncClientHttpRequest request2 = (HttpComponentsAsyncClientHttpRequest)
|
||||
factory.createAsyncRequest(uri, HttpMethod.GET);
|
||||
Object requestConfigAttribute = request2.getHttpContext().getAttribute(HttpClientContext.REQUEST_CONFIG);
|
||||
assertThat(requestConfigAttribute).isNotNull();
|
||||
RequestConfig requestConfig = (RequestConfig) requestConfigAttribute;
|
||||
|
||||
assertThat(requestConfig.getConnectionRequestTimeout()).isEqualTo(4567);
|
||||
// No way to access the request config of the HTTP client so no way to "merge" our customizations
|
||||
assertThat(requestConfig.getConnectTimeout()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class Netty4AsyncClientHttpRequestFactoryTests extends AbstractAsyncHttpRequestFactoryTests {
|
||||
|
||||
private static EventLoopGroup eventLoopGroup;
|
||||
|
||||
|
||||
@BeforeAll
|
||||
public static void createEventLoopGroup() {
|
||||
eventLoopGroup = new NioEventLoopGroup();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdownEventLoopGroup() throws InterruptedException {
|
||||
eventLoopGroup.shutdownGracefully().sync();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected AsyncClientHttpRequestFactory createRequestFactory() {
|
||||
return new Netty4ClientHttpRequestFactory(eventLoopGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
super.httpMethods();
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class Netty4ClientHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests {
|
||||
|
||||
private static EventLoopGroup eventLoopGroup;
|
||||
|
||||
|
||||
@BeforeAll
|
||||
public static void createEventLoopGroup() {
|
||||
eventLoopGroup = new NioEventLoopGroup();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdownEventLoopGroup() throws InterruptedException {
|
||||
eventLoopGroup.shutdownGracefully().sync();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected ClientHttpRequestFactory createRequestFactory() {
|
||||
return new Netty4ClientHttpRequestFactory(eventLoopGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
super.httpMethods();
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.http.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* @author Roy Clarkson
|
||||
*/
|
||||
public class OkHttp3AsyncClientHttpRequestFactoryTests extends AbstractAsyncHttpRequestFactoryTests {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected AsyncClientHttpRequestFactory createRequestFactory() {
|
||||
return new OkHttp3ClientHttpRequestFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
super.httpMethods();
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,669 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.web.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link AsyncRestTemplate}.
|
||||
*
|
||||
* <h3>Logging configuration for {@code MockWebServer}</h3>
|
||||
*
|
||||
* <p>In order for our log4j2 configuration to be used in an IDE, you must
|
||||
* set the following system property before running any tests — for
|
||||
* example, in <em>Run Configurations</em> in Eclipse.
|
||||
*
|
||||
* <pre class="code">
|
||||
* -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
|
||||
* </pre>
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class AsyncRestTemplateIntegrationTests extends AbstractMockWebServerTests {
|
||||
|
||||
private final AsyncRestTemplate template = new AsyncRestTemplate(
|
||||
new org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory());
|
||||
|
||||
|
||||
@Test
|
||||
public void getEntity() throws Exception {
|
||||
Future<ResponseEntity<String>> future = template.getForEntity(baseUrl + "/{method}", String.class, "get");
|
||||
ResponseEntity<String> entity = future.get();
|
||||
assertThat(entity.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
assertThat(entity.getHeaders().isEmpty()).as("No headers").isFalse();
|
||||
assertThat(entity.getHeaders().getContentType()).as("Invalid content-type").isEqualTo(textContentType);
|
||||
assertThat(entity.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntityFromCompletable() throws Exception {
|
||||
ListenableFuture<ResponseEntity<String>> future = template.getForEntity(baseUrl + "/{method}", String.class, "get");
|
||||
ResponseEntity<String> entity = future.completable().get();
|
||||
assertThat(entity.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
assertThat(entity.getHeaders().isEmpty()).as("No headers").isFalse();
|
||||
assertThat(entity.getHeaders().getContentType()).as("Invalid content-type").isEqualTo(textContentType);
|
||||
assertThat(entity.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleFutureGets() throws Exception {
|
||||
Future<ResponseEntity<String>> future = template.getForEntity(baseUrl + "/{method}", String.class, "get");
|
||||
future.get();
|
||||
future.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntityCallback() throws Exception {
|
||||
ListenableFuture<ResponseEntity<String>> futureEntity =
|
||||
template.getForEntity(baseUrl + "/{method}", String.class, "get");
|
||||
futureEntity.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseEntity<String> entity) {
|
||||
assertThat(entity.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
assertThat(entity.getHeaders().isEmpty()).as("No headers").isFalse();
|
||||
assertThat(entity.getHeaders().getContentType()).as("Invalid content-type").isEqualTo(textContentType);
|
||||
assertThat(entity.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(futureEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntityCallbackWithLambdas() throws Exception {
|
||||
ListenableFuture<ResponseEntity<String>> futureEntity =
|
||||
template.getForEntity(baseUrl + "/{method}", String.class, "get");
|
||||
futureEntity.addCallback(entity -> {
|
||||
assertThat(entity.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
assertThat(entity.getHeaders().isEmpty()).as("No headers").isFalse();
|
||||
assertThat(entity.getHeaders().getContentType()).as("Invalid content-type").isEqualTo(textContentType);
|
||||
assertThat(entity.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
}, ex -> fail(ex.getMessage()));
|
||||
waitTillDone(futureEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNoResponse() throws Exception {
|
||||
Future<ResponseEntity<String>> futureEntity = template.getForEntity(baseUrl + "/get/nothing", String.class);
|
||||
ResponseEntity<String> entity = futureEntity.get();
|
||||
assertThat(entity.getBody()).as("Invalid content").isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNoContentTypeHeader() throws Exception {
|
||||
Future<ResponseEntity<byte[]>> futureEntity = template.getForEntity(baseUrl + "/get/nocontenttype", byte[].class);
|
||||
ResponseEntity<byte[]> responseEntity = futureEntity.get();
|
||||
assertThat(responseEntity.getBody()).as("Invalid content").isEqualTo(helloWorld.getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNoContent() throws Exception {
|
||||
Future<ResponseEntity<String>> responseFuture = template.getForEntity(baseUrl + "/status/nocontent", String.class);
|
||||
ResponseEntity<String> entity = responseFuture.get();
|
||||
assertThat(entity.getStatusCode()).as("Invalid response code").isEqualTo(HttpStatus.NO_CONTENT);
|
||||
assertThat(entity.getBody()).as("Invalid content").isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNotModified() throws Exception {
|
||||
Future<ResponseEntity<String>> responseFuture = template.getForEntity(baseUrl + "/status/notmodified", String.class);
|
||||
ResponseEntity<String> entity = responseFuture.get();
|
||||
assertThat(entity.getStatusCode()).as("Invalid response code").isEqualTo(HttpStatus.NOT_MODIFIED);
|
||||
assertThat(entity.getBody()).as("Invalid content").isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headForHeaders() throws Exception {
|
||||
Future<HttpHeaders> headersFuture = template.headForHeaders(baseUrl + "/get");
|
||||
HttpHeaders headers = headersFuture.get();
|
||||
assertThat(headers.containsKey("Content-Type")).as("No Content-Type header").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headForHeadersCallback() throws Exception {
|
||||
ListenableFuture<HttpHeaders> headersFuture = template.headForHeaders(baseUrl + "/get");
|
||||
headersFuture.addCallback(new ListenableFutureCallback<HttpHeaders>() {
|
||||
@Override
|
||||
public void onSuccess(HttpHeaders result) {
|
||||
assertThat(result.containsKey("Content-Type")).as("No Content-Type header").isTrue();
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(headersFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headForHeadersCallbackWithLambdas() throws Exception {
|
||||
ListenableFuture<HttpHeaders> headersFuture = template.headForHeaders(baseUrl + "/get");
|
||||
headersFuture.addCallback(result -> assertThat(result.containsKey("Content-Type")).as("No Content-Type header").isTrue(), ex -> fail(ex.getMessage()));
|
||||
waitTillDone(headersFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForLocation() throws Exception {
|
||||
HttpHeaders entityHeaders = new HttpHeaders();
|
||||
entityHeaders.setContentType(new MediaType("text", "plain", StandardCharsets.ISO_8859_1));
|
||||
HttpEntity<String> entity = new HttpEntity<>(helloWorld, entityHeaders);
|
||||
Future<URI> locationFuture = template.postForLocation(baseUrl + "/{method}", entity, "post");
|
||||
URI location = locationFuture.get();
|
||||
assertThat(location).as("Invalid location").isEqualTo(new URI(baseUrl + "/post/1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForLocationCallback() throws Exception {
|
||||
HttpHeaders entityHeaders = new HttpHeaders();
|
||||
entityHeaders.setContentType(new MediaType("text", "plain", StandardCharsets.ISO_8859_1));
|
||||
HttpEntity<String> entity = new HttpEntity<>(helloWorld, entityHeaders);
|
||||
final URI expected = new URI(baseUrl + "/post/1");
|
||||
ListenableFuture<URI> locationFuture = template.postForLocation(baseUrl + "/{method}", entity, "post");
|
||||
locationFuture.addCallback(new ListenableFutureCallback<URI>() {
|
||||
@Override
|
||||
public void onSuccess(URI result) {
|
||||
assertThat(result).as("Invalid location").isEqualTo(expected);
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(locationFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForLocationCallbackWithLambdas() throws Exception {
|
||||
HttpHeaders entityHeaders = new HttpHeaders();
|
||||
entityHeaders.setContentType(new MediaType("text", "plain", StandardCharsets.ISO_8859_1));
|
||||
HttpEntity<String> entity = new HttpEntity<>(helloWorld, entityHeaders);
|
||||
final URI expected = new URI(baseUrl + "/post/1");
|
||||
ListenableFuture<URI> locationFuture = template.postForLocation(baseUrl + "/{method}", entity, "post");
|
||||
locationFuture.addCallback(result -> assertThat(result).as("Invalid location").isEqualTo(expected),
|
||||
ex -> fail(ex.getMessage()));
|
||||
waitTillDone(locationFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForEntity() throws Exception {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
Future<ResponseEntity<String>> responseEntityFuture =
|
||||
template.postForEntity(baseUrl + "/{method}", requestEntity, String.class, "post");
|
||||
ResponseEntity<String> responseEntity = responseEntityFuture.get();
|
||||
assertThat(responseEntity.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForEntityCallback() throws Exception {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
ListenableFuture<ResponseEntity<String>> responseEntityFuture =
|
||||
template.postForEntity(baseUrl + "/{method}", requestEntity, String.class, "post");
|
||||
responseEntityFuture.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseEntity<String> result) {
|
||||
assertThat(result.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(responseEntityFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForEntityCallbackWithLambdas() throws Exception {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
ListenableFuture<ResponseEntity<String>> responseEntityFuture =
|
||||
template.postForEntity(baseUrl + "/{method}", requestEntity, String.class, "post");
|
||||
responseEntityFuture.addCallback(
|
||||
result -> assertThat(result.getBody()).as("Invalid content").isEqualTo(helloWorld),
|
||||
ex -> fail(ex.getMessage()));
|
||||
waitTillDone(responseEntityFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void put() throws Exception {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
Future<?> responseEntityFuture = template.put(baseUrl + "/{method}", requestEntity, "put");
|
||||
responseEntityFuture.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putCallback() throws Exception {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
ListenableFuture<?> responseEntityFuture = template.put(baseUrl + "/{method}", requestEntity, "put");
|
||||
responseEntityFuture.addCallback(new ListenableFutureCallback<Object>() {
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(responseEntityFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete() throws Exception {
|
||||
Future<?> deletedFuture = template.delete(new URI(baseUrl + "/delete"));
|
||||
deletedFuture.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteCallback() throws Exception {
|
||||
ListenableFuture<?> deletedFuture = template.delete(new URI(baseUrl + "/delete"));
|
||||
deletedFuture.addCallback(new ListenableFutureCallback<Object>() {
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(deletedFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteCallbackWithLambdas() throws Exception {
|
||||
ListenableFuture<?> deletedFuture = template.delete(new URI(baseUrl + "/delete"));
|
||||
deletedFuture.addCallback(result -> assertThat(result).isNull(), ex -> fail(ex.getMessage()));
|
||||
waitTillDone(deletedFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void identicalExceptionThroughGetAndCallback() throws Exception {
|
||||
final HttpClientErrorException[] callbackException = new HttpClientErrorException[1];
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ListenableFuture<?> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
|
||||
future.addCallback(new ListenableFutureCallback<Object>() {
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
fail("onSuccess not expected");
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
boolean condition = ex instanceof HttpClientErrorException;
|
||||
assertThat(condition).isTrue();
|
||||
callbackException[0] = (HttpClientErrorException) ex;
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
future.get();
|
||||
fail("Exception expected");
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
boolean condition = cause instanceof HttpClientErrorException;
|
||||
assertThat(condition).isTrue();
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
assertThat(cause).isSameAs(callbackException[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notFoundGet() throws Exception {
|
||||
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> {
|
||||
Future<?> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
|
||||
future.get();
|
||||
})
|
||||
.withCauseInstanceOf(HttpClientErrorException.class)
|
||||
.satisfies(ex -> {
|
||||
HttpClientErrorException cause = (HttpClientErrorException) ex.getCause();
|
||||
assertThat(cause.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
assertThat(cause.getStatusText()).isNotNull();
|
||||
assertThat(cause.getResponseBodyAsString()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notFoundCallback() throws Exception {
|
||||
ListenableFuture<?> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
|
||||
future.addCallback(new ListenableFutureCallback<Object>() {
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
fail("onSuccess not expected");
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
boolean condition = t instanceof HttpClientErrorException;
|
||||
assertThat(condition).isTrue();
|
||||
HttpClientErrorException ex = (HttpClientErrorException) t;
|
||||
assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
assertThat(ex.getStatusText()).isNotNull();
|
||||
assertThat(ex.getResponseBodyAsString()).isNotNull();
|
||||
}
|
||||
});
|
||||
waitTillDone(future);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notFoundCallbackWithLambdas() throws Exception {
|
||||
ListenableFuture<?> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
|
||||
future.addCallback(result -> fail("onSuccess not expected"), ex -> {
|
||||
boolean condition = ex instanceof HttpClientErrorException;
|
||||
assertThat(condition).isTrue();
|
||||
HttpClientErrorException hcex = (HttpClientErrorException) ex;
|
||||
assertThat(hcex.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
assertThat(hcex.getStatusText()).isNotNull();
|
||||
assertThat(hcex.getResponseBodyAsString()).isNotNull();
|
||||
});
|
||||
waitTillDone(future);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverError() throws Exception {
|
||||
try {
|
||||
Future<Void> future = template.execute(baseUrl + "/status/server", HttpMethod.GET, null, null);
|
||||
future.get();
|
||||
fail("HttpServerErrorException expected");
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
boolean condition = ex.getCause() instanceof HttpServerErrorException;
|
||||
assertThat(condition).isTrue();
|
||||
HttpServerErrorException cause = (HttpServerErrorException)ex.getCause();
|
||||
|
||||
assertThat(cause.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
assertThat(cause.getStatusText()).isNotNull();
|
||||
assertThat(cause.getResponseBodyAsString()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverErrorCallback() throws Exception {
|
||||
ListenableFuture<Void> future = template.execute(baseUrl + "/status/server", HttpMethod.GET, null, null);
|
||||
future.addCallback(new ListenableFutureCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
fail("onSuccess not expected");
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
boolean condition = ex instanceof HttpServerErrorException;
|
||||
assertThat(condition).isTrue();
|
||||
HttpServerErrorException hsex = (HttpServerErrorException) ex;
|
||||
assertThat(hsex.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
assertThat(hsex.getStatusText()).isNotNull();
|
||||
assertThat(hsex.getResponseBodyAsString()).isNotNull();
|
||||
}
|
||||
});
|
||||
waitTillDone(future);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverErrorCallbackWithLambdas() throws Exception {
|
||||
ListenableFuture<Void> future = template.execute(baseUrl + "/status/server", HttpMethod.GET, null, null);
|
||||
future.addCallback(result -> fail("onSuccess not expected"), ex -> {
|
||||
boolean condition = ex instanceof HttpServerErrorException;
|
||||
assertThat(condition).isTrue();
|
||||
HttpServerErrorException hsex = (HttpServerErrorException) ex;
|
||||
assertThat(hsex.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
assertThat(hsex.getStatusText()).isNotNull();
|
||||
assertThat(hsex.getResponseBodyAsString()).isNotNull();
|
||||
});
|
||||
waitTillDone(future);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsForAllow() throws Exception {
|
||||
Future<Set<HttpMethod>> allowedFuture = template.optionsForAllow(new URI(baseUrl + "/get"));
|
||||
Set<HttpMethod> allowed = allowedFuture.get();
|
||||
assertThat(allowed).as("Invalid response").isEqualTo(EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD, HttpMethod.TRACE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsForAllowCallback() throws Exception {
|
||||
ListenableFuture<Set<HttpMethod>> allowedFuture = template.optionsForAllow(new URI(baseUrl + "/get"));
|
||||
allowedFuture.addCallback(new ListenableFutureCallback<Set<HttpMethod>>() {
|
||||
@Override
|
||||
public void onSuccess(Set<HttpMethod> result) {
|
||||
assertThat(result).as("Invalid response").isEqualTo(EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS,
|
||||
HttpMethod.HEAD, HttpMethod.TRACE));
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(allowedFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsForAllowCallbackWithLambdas() throws Exception{
|
||||
ListenableFuture<Set<HttpMethod>> allowedFuture = template.optionsForAllow(new URI(baseUrl + "/get"));
|
||||
allowedFuture.addCallback(result -> assertThat(result).as("Invalid response").isEqualTo(EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD,HttpMethod.TRACE)),
|
||||
ex -> fail(ex.getMessage()));
|
||||
waitTillDone(allowedFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void exchangeGet() throws Exception {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("MyHeader", "MyValue");
|
||||
HttpEntity<?> requestEntity = new HttpEntity(requestHeaders);
|
||||
Future<ResponseEntity<String>> responseFuture =
|
||||
template.exchange(baseUrl + "/{method}", HttpMethod.GET, requestEntity, String.class, "get");
|
||||
ResponseEntity<String> response = responseFuture.get();
|
||||
assertThat(response.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void exchangeGetCallback() throws Exception {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("MyHeader", "MyValue");
|
||||
HttpEntity<?> requestEntity = new HttpEntity(requestHeaders);
|
||||
ListenableFuture<ResponseEntity<String>> responseFuture =
|
||||
template.exchange(baseUrl + "/{method}", HttpMethod.GET, requestEntity, String.class, "get");
|
||||
responseFuture.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseEntity<String> result) {
|
||||
assertThat(result.getBody()).as("Invalid content").isEqualTo(helloWorld);
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(responseFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void exchangeGetCallbackWithLambdas() throws Exception {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("MyHeader", "MyValue");
|
||||
HttpEntity<?> requestEntity = new HttpEntity(requestHeaders);
|
||||
ListenableFuture<ResponseEntity<String>> responseFuture =
|
||||
template.exchange(baseUrl + "/{method}", HttpMethod.GET, requestEntity, String.class, "get");
|
||||
responseFuture.addCallback(result -> assertThat(result.getBody()).as("Invalid content").isEqualTo(helloWorld), ex -> fail(ex.getMessage()));
|
||||
waitTillDone(responseFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exchangePost() throws Exception {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("MyHeader", "MyValue");
|
||||
requestHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld, requestHeaders);
|
||||
Future<ResponseEntity<Void>> resultFuture =
|
||||
template.exchange(baseUrl + "/{method}", HttpMethod.POST, requestEntity, Void.class, "post");
|
||||
ResponseEntity<Void> result = resultFuture.get();
|
||||
assertThat(result.getHeaders().getLocation()).as("Invalid location").isEqualTo(new URI(baseUrl + "/post/1"));
|
||||
assertThat(result.hasBody()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exchangePostCallback() throws Exception {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("MyHeader", "MyValue");
|
||||
requestHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld, requestHeaders);
|
||||
ListenableFuture<ResponseEntity<Void>> resultFuture =
|
||||
template.exchange(baseUrl + "/{method}", HttpMethod.POST, requestEntity, Void.class, "post");
|
||||
final URI expected =new URI(baseUrl + "/post/1");
|
||||
resultFuture.addCallback(new ListenableFutureCallback<ResponseEntity<Void>>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseEntity<Void> result) {
|
||||
assertThat(result.getHeaders().getLocation()).as("Invalid location").isEqualTo(expected);
|
||||
assertThat(result.hasBody()).isFalse();
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
waitTillDone(resultFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exchangePostCallbackWithLambdas() throws Exception {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("MyHeader", "MyValue");
|
||||
requestHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld, requestHeaders);
|
||||
ListenableFuture<ResponseEntity<Void>> resultFuture =
|
||||
template.exchange(baseUrl + "/{method}", HttpMethod.POST, requestEntity, Void.class, "post");
|
||||
final URI expected =new URI(baseUrl + "/post/1");
|
||||
resultFuture.addCallback(result -> {
|
||||
assertThat(result.getHeaders().getLocation()).as("Invalid location").isEqualTo(expected);
|
||||
assertThat(result.hasBody()).isFalse();
|
||||
}, ex -> fail(ex.getMessage()));
|
||||
waitTillDone(resultFuture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartFormData() throws Exception {
|
||||
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
|
||||
parts.add("name 1", "value 1");
|
||||
parts.add("name 2", "value 2+1");
|
||||
parts.add("name 2", "value 2+2");
|
||||
Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg");
|
||||
parts.add("logo", logo);
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> requestBody = new HttpEntity<>(parts);
|
||||
Future<URI> future = template.postForLocation(baseUrl + "/multipartFormData", requestBody);
|
||||
future.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAndInterceptResponse() throws Exception {
|
||||
RequestInterceptor interceptor = new RequestInterceptor();
|
||||
template.setInterceptors(Collections.singletonList(interceptor));
|
||||
ListenableFuture<ResponseEntity<String>> future = template.getForEntity(baseUrl + "/get", String.class);
|
||||
|
||||
interceptor.latch.await(5, TimeUnit.SECONDS);
|
||||
assertThat(interceptor.response).isNotNull();
|
||||
assertThat(interceptor.response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(interceptor.exception).isNull();
|
||||
assertThat(future.get().getBody()).isEqualTo(helloWorld);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAndInterceptError() throws Exception {
|
||||
RequestInterceptor interceptor = new RequestInterceptor();
|
||||
template.setInterceptors(Collections.singletonList(interceptor));
|
||||
template.getForEntity(baseUrl + "/status/notfound", String.class);
|
||||
|
||||
interceptor.latch.await(5, TimeUnit.SECONDS);
|
||||
assertThat(interceptor.response).isNotNull();
|
||||
assertThat(interceptor.response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
assertThat(interceptor.exception).isNull();
|
||||
}
|
||||
|
||||
private void waitTillDone(ListenableFuture<?> future) {
|
||||
while (!future.isDone()) {
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class RequestInterceptor implements org.springframework.http.client.AsyncClientHttpRequestInterceptor {
|
||||
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
private volatile ClientHttpResponse response;
|
||||
|
||||
private volatile Throwable exception;
|
||||
|
||||
@Override
|
||||
public ListenableFuture<ClientHttpResponse> intercept(HttpRequest request, byte[] body,
|
||||
org.springframework.http.client.AsyncClientHttpRequestExecution execution) throws IOException {
|
||||
|
||||
ListenableFuture<ClientHttpResponse> future = execution.executeAsync(request, body);
|
||||
future.addCallback(
|
||||
resp -> {
|
||||
response = resp;
|
||||
this.latch.countDown();
|
||||
},
|
||||
ex -> {
|
||||
exception = ex;
|
||||
this.latch.countDown();
|
||||
});
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -92,7 +92,6 @@ class RestTemplateIntegrationTests extends AbstractMockWebServerTests {
|
|||
return Stream.of(
|
||||
new SimpleClientHttpRequestFactory(),
|
||||
new HttpComponentsClientHttpRequestFactory(),
|
||||
new org.springframework.http.client.Netty4ClientHttpRequestFactory(),
|
||||
new OkHttp3ClientHttpRequestFactory()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -344,13 +344,6 @@ to `multipart/form-data` by the `FormHttpMessageConverter`. If the `MultiValueMa
|
|||
If necessary the `Content-Type` may also be set explicitly.
|
||||
|
||||
|
||||
[[rest-async-resttemplate]]
|
||||
=== Using `AsyncRestTemplate` (Deprecated)
|
||||
|
||||
The `AsyncRestTemplate` is deprecated. For all use cases where you might consider using
|
||||
`AsyncRestTemplate`, use the <<web-reactive.adoc#webflux-client, WebClient>> instead.
|
||||
|
||||
|
||||
|
||||
[[remoting]]
|
||||
== Remoting and Web Services
|
||||
|
|
Loading…
Reference in New Issue