Add AsyncRestTemplate
Added AsyncRestTemplate, the asynchronous counterpart to the RestTemplate that was introduced in Spring 3. All methods on the AsyncRestTemplate are similar to those found on the synchronous RestTemplatem, except that they return Future wrappers instead of concrete results. To enable this, this commit introduces the AsyncClientHttpRequest and AsyncClientHttpRequestFactory, similar to the ClientHttpRequest and ClientHttpRequestFactory, except that ClientHttpRequest returns a Future<ClientHttpResponse> for the execute method. Two implementations of these interfaces are provided, one based on the HttpURLConnection incombination with a Spring AsyncTaskExecutor and one based on Apache HttpComponents HttpAsyncClient. Issue: SPR-8804
This commit is contained in:
committed by
Rossen Stoyanchev
parent
89b53cfcd5
commit
ebcee26d57
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
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;
|
||||
|
||||
public abstract class AbstractAsyncHttpRequestFactoryTestCase extends
|
||||
AbstractJettyServerTestCase {
|
||||
|
||||
protected AsyncClientHttpRequestFactory factory;
|
||||
|
||||
@Before
|
||||
public final void createFactory() throws Exception {
|
||||
factory = createRequestFactory();
|
||||
if (factory instanceof InitializingBean) {
|
||||
((InitializingBean) factory).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract AsyncClientHttpRequestFactory createRequestFactory();
|
||||
|
||||
@Test
|
||||
public void status() throws Exception {
|
||||
URI uri = new URI(baseUrl + "/status/notfound");
|
||||
AsyncClientHttpRequest request = factory.createAsyncRequest(uri, HttpMethod.GET);
|
||||
assertEquals("Invalid HTTP method", HttpMethod.GET, request.getMethod());
|
||||
assertEquals("Invalid HTTP URI", uri, request.getURI());
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
ClientHttpResponse response = futureResponse.get();
|
||||
assertEquals("Invalid status code", HttpStatus.NOT_FOUND,
|
||||
response.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void echo() throws Exception {
|
||||
AsyncClientHttpRequest
|
||||
request = factory.createAsyncRequest(new URI(baseUrl + "/echo"),
|
||||
HttpMethod.PUT);
|
||||
assertEquals("Invalid HTTP method", HttpMethod.PUT, request.getMethod());
|
||||
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(new StreamingHttpOutputMessage.Body() {
|
||||
@Override
|
||||
public void writeTo(OutputStream outputStream) throws IOException {
|
||||
StreamUtils.copy(body, outputStream);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
StreamUtils.copy(body, request.getBody());
|
||||
}
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
ClientHttpResponse response = futureResponse.get();
|
||||
try {
|
||||
assertEquals("Invalid status code", HttpStatus.OK, response.getStatusCode());
|
||||
assertTrue("Header not found", response.getHeaders().containsKey(headerName));
|
||||
assertEquals("Header value not found", Arrays.asList(headerValue1, headerValue2),
|
||||
response.getHeaders().get(headerName));
|
||||
byte[] result = FileCopyUtils.copyToByteArray(response.getBody());
|
||||
assertTrue("Invalid body", Arrays.equals(body, result));
|
||||
}
|
||||
finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void multipleWrites() throws Exception {
|
||||
AsyncClientHttpRequest
|
||||
request = 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(new StreamingHttpOutputMessage.Body() {
|
||||
@Override
|
||||
public void writeTo(OutputStream outputStream) throws IOException {
|
||||
StreamUtils.copy(body, outputStream);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
StreamUtils.copy(body, request.getBody());
|
||||
}
|
||||
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
ClientHttpResponse response = futureResponse.get();
|
||||
try {
|
||||
FileCopyUtils.copy(body, request.getBody());
|
||||
}
|
||||
finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void headersAfterExecute() throws Exception {
|
||||
AsyncClientHttpRequest
|
||||
request = 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();
|
||||
ClientHttpResponse response = futureResponse.get();
|
||||
try {
|
||||
request.getHeaders().add("MyHeader", "value");
|
||||
}
|
||||
finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@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 {
|
||||
ClientHttpResponse response = null;
|
||||
try {
|
||||
AsyncClientHttpRequest request = factory.createAsyncRequest(
|
||||
new URI(baseUrl + "/methods/" + path), method);
|
||||
|
||||
Future<ClientHttpResponse> futureResponse = request.executeAsync();
|
||||
response = futureResponse.get();
|
||||
assertEquals("Invalid response status", HttpStatus.OK, response.getStatusCode());
|
||||
assertEquals("Invalid method", path.toUpperCase(Locale.ENGLISH), request.getMethod().name());
|
||||
}
|
||||
finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,70 +17,27 @@
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.StreamingHttpOutputMessage;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
/** @author Arjen Poutsma */
|
||||
public abstract class AbstractHttpRequestFactoryTestCase extends
|
||||
AbstractJettyServerTestCase {
|
||||
|
||||
protected ClientHttpRequestFactory factory;
|
||||
|
||||
protected static String baseUrl;
|
||||
|
||||
private static Server jettyServer;
|
||||
|
||||
@BeforeClass
|
||||
public static void startJettyServer() throws Exception {
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
jettyServer = new Server(port);
|
||||
baseUrl = "http://localhost:" + port;
|
||||
|
||||
ServletContextHandler handler = new ServletContextHandler();
|
||||
handler.setContextPath("/");
|
||||
|
||||
handler.addServlet(new ServletHolder(new EchoServlet()), "/echo");
|
||||
handler.addServlet(new ServletHolder(new EchoServlet()), "/echo");
|
||||
handler.addServlet(new ServletHolder(new StatusServlet(200)), "/status/ok");
|
||||
handler.addServlet(new ServletHolder(new StatusServlet(404)), "/status/notfound");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("DELETE")), "/methods/delete");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("GET")), "/methods/get");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("HEAD")), "/methods/head");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("OPTIONS")), "/methods/options");
|
||||
handler.addServlet(new ServletHolder(new PostServlet()), "/methods/post");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("PUT")), "/methods/put");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("PATCH")), "/methods/patch");
|
||||
|
||||
jettyServer.setHandler(handler);
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public final void createFactory() {
|
||||
factory = createRequestFactory();
|
||||
@@ -88,13 +45,6 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
|
||||
protected abstract ClientHttpRequestFactory createRequestFactory();
|
||||
|
||||
@AfterClass
|
||||
public static void stopJettyServer() throws Exception {
|
||||
if (jettyServer != null) {
|
||||
jettyServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void status() throws Exception {
|
||||
URI uri = new URI(baseUrl + "/status/notfound");
|
||||
@@ -210,85 +160,4 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet that sets a given status code.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class StatusServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
|
||||
private StatusServlet(int sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
|
||||
((HttpServletResponse) response).setStatus(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class MethodServlet extends GenericServlet {
|
||||
|
||||
private final String method;
|
||||
|
||||
private MethodServlet(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
|
||||
HttpServletRequest httpReq = (HttpServletRequest) req;
|
||||
assertEquals("Invalid HTTP method", method, httpReq.getMethod());
|
||||
res.setContentLength(0);
|
||||
((HttpServletResponse) res).setStatus(200);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class PostServlet extends MethodServlet {
|
||||
|
||||
private PostServlet() {
|
||||
super("POST");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
|
||||
super.service(req, res);
|
||||
long contentLength = req.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
InputStream in = req.getInputStream();
|
||||
long byteCount = 0;
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
byteCount += bytesRead;
|
||||
}
|
||||
assertEquals("Invalid content-length", contentLength, byteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class EchoServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
echo(req, resp);
|
||||
}
|
||||
|
||||
private void echo(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
for (Enumeration e1 = request.getHeaderNames(); e1.hasMoreElements();) {
|
||||
String headerName = (String) e1.nextElement();
|
||||
for (Enumeration e2 = request.getHeaders(headerName); e2.hasMoreElements();) {
|
||||
String headerValue = (String) e2.nextElement();
|
||||
response.addHeader(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
FileCopyUtils.copy(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.SocketUtils;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
public class AbstractJettyServerTestCase {
|
||||
|
||||
protected static String baseUrl;
|
||||
|
||||
private static Server jettyServer;
|
||||
|
||||
@BeforeClass
|
||||
public static void startJettyServer() throws Exception {
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
jettyServer = new Server(port);
|
||||
baseUrl = "http://localhost:" + port;
|
||||
|
||||
ServletContextHandler handler = new ServletContextHandler();
|
||||
handler.setContextPath("/");
|
||||
|
||||
handler.addServlet(new ServletHolder(new EchoServlet()), "/echo");
|
||||
handler.addServlet(new ServletHolder(new EchoServlet()), "/echo");
|
||||
handler.addServlet(new ServletHolder(new StatusServlet(200)), "/status/ok");
|
||||
handler.addServlet(new ServletHolder(new StatusServlet(404)), "/status/notfound");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("DELETE")), "/methods/delete");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("GET")), "/methods/get");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("HEAD")), "/methods/head");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("OPTIONS")), "/methods/options");
|
||||
handler.addServlet(new ServletHolder(new PostServlet()), "/methods/post");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("PUT")), "/methods/put");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("PATCH")), "/methods/patch");
|
||||
|
||||
jettyServer.setHandler(handler);
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopJettyServer() throws Exception {
|
||||
if (jettyServer != null) {
|
||||
jettyServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet that sets a given status code.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class StatusServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
|
||||
private StatusServlet(int sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest request, ServletResponse response) throws
|
||||
ServletException, IOException {
|
||||
((HttpServletResponse) response).setStatus(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class MethodServlet extends GenericServlet {
|
||||
|
||||
private final String method;
|
||||
|
||||
private MethodServlet(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
|
||||
HttpServletRequest httpReq = (HttpServletRequest) req;
|
||||
assertEquals("Invalid HTTP method", method, httpReq.getMethod());
|
||||
res.setContentLength(0);
|
||||
((HttpServletResponse) res).setStatus(200);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class PostServlet extends MethodServlet {
|
||||
|
||||
private PostServlet() {
|
||||
super("POST");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
|
||||
super.service(req, res);
|
||||
long contentLength = req.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
InputStream in = req.getInputStream();
|
||||
long byteCount = 0;
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
byteCount += bytesRead;
|
||||
}
|
||||
assertEquals("Invalid content-length", contentLength, byteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class EchoServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
echo(req, resp);
|
||||
}
|
||||
|
||||
private void echo(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
for (Enumeration e1 = request.getHeaderNames(); e1.hasMoreElements();) {
|
||||
String headerName = (String) e1.nextElement();
|
||||
for (Enumeration e2 = request.getHeaders(headerName); e2.hasMoreElements();) {
|
||||
String headerValue = (String) e2.nextElement();
|
||||
response.addHeader(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
FileCopyUtils.copy(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.net.ProtocolException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
public class BufferedSimpleAsyncHttpRequestFactoryTests extends AbstractAsyncHttpRequestFactoryTestCase {
|
||||
|
||||
@Override
|
||||
protected AsyncClientHttpRequestFactory createRequestFactory() {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
|
||||
requestFactory.setTaskExecutor(taskExecutor);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
try {
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
catch (ProtocolException ex) {
|
||||
// Currently HttpURLConnection does not support HTTP PATCH
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class HttpComponentsAsyncClientHttpRequestFactoryTests extends AbstractAsyncHttpRequestFactoryTestCase {
|
||||
|
||||
@Override
|
||||
protected AsyncClientHttpRequestFactory createRequestFactory() {
|
||||
return new HttpComponentsAsyncClientHttpRequestFactory();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void httpMethods() throws Exception {
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileItemFactory;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.SocketUtils;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
public class AbstractJettyServerTestCase {
|
||||
|
||||
protected static String helloWorld = "H\u00e9llo W\u00f6rld";
|
||||
|
||||
protected static String baseUrl;
|
||||
|
||||
protected static MediaType contentType;
|
||||
|
||||
private static Server jettyServer;
|
||||
|
||||
@BeforeClass
|
||||
public static void startJettyServer() throws Exception {
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
jettyServer = new Server(port);
|
||||
baseUrl = "http://localhost:" + port;
|
||||
ServletContextHandler handler = new ServletContextHandler();
|
||||
byte[] bytes = helloWorld.getBytes("UTF-8");
|
||||
contentType = new MediaType("text", "plain", Collections
|
||||
.singletonMap("charset", "UTF-8"));
|
||||
handler.addServlet(new ServletHolder(new GetServlet(bytes, contentType)), "/get");
|
||||
handler.addServlet(new ServletHolder(new GetServlet(new byte[0], contentType)), "/get/nothing");
|
||||
handler.addServlet(new ServletHolder(new GetServlet(bytes, null)), "/get/nocontenttype");
|
||||
handler.addServlet(
|
||||
new ServletHolder(new PostServlet(helloWorld, baseUrl + "/post/1", bytes, contentType)),
|
||||
"/post");
|
||||
handler.addServlet(new ServletHolder(new StatusCodeServlet(204)), "/status/nocontent");
|
||||
handler.addServlet(new ServletHolder(new StatusCodeServlet(304)), "/status/notmodified");
|
||||
handler.addServlet(new ServletHolder(new ErrorServlet(404)), "/status/notfound");
|
||||
handler.addServlet(new ServletHolder(new ErrorServlet(500)), "/status/server");
|
||||
handler.addServlet(new ServletHolder(new UriServlet()), "/uri/*");
|
||||
handler.addServlet(new ServletHolder(new MultipartServlet()), "/multipart");
|
||||
handler.addServlet(new ServletHolder(new DeleteServlet()), "/delete");
|
||||
handler.addServlet(
|
||||
new ServletHolder(new PutServlet(helloWorld, bytes, contentType)),
|
||||
"/put");
|
||||
jettyServer.setHandler(handler);
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopJettyServer() throws Exception {
|
||||
if (jettyServer != null) {
|
||||
jettyServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/** Servlet that sets the given status code. */
|
||||
@SuppressWarnings("serial")
|
||||
private static class StatusCodeServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
|
||||
private StatusCodeServlet(int sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest request, ServletResponse response) throws
|
||||
ServletException, IOException {
|
||||
((HttpServletResponse) response).setStatus(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/** Servlet that returns an error message for a given status code. */
|
||||
@SuppressWarnings("serial")
|
||||
private static class ErrorServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
|
||||
private ErrorServlet(int sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
|
||||
((HttpServletResponse) response).sendError(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class GetServlet extends HttpServlet {
|
||||
|
||||
private final byte[] buf;
|
||||
|
||||
private final MediaType contentType;
|
||||
|
||||
private GetServlet(byte[] buf, MediaType contentType) {
|
||||
this.buf = buf;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
if (contentType != null) {
|
||||
response.setContentType(contentType.toString());
|
||||
}
|
||||
response.setContentLength(buf.length);
|
||||
FileCopyUtils.copy(buf, response.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class PostServlet extends HttpServlet {
|
||||
|
||||
private final String s;
|
||||
|
||||
private final String location;
|
||||
|
||||
private final byte[] buf;
|
||||
|
||||
private final MediaType contentType;
|
||||
|
||||
private PostServlet(String s, String location, byte[] buf, MediaType contentType) {
|
||||
this.s = s;
|
||||
this.location = location;
|
||||
this.buf = buf;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
assertTrue("Invalid request content-length", request.getContentLength() > 0);
|
||||
assertNotNull("No content-type", request.getContentType());
|
||||
String body = FileCopyUtils.copyToString(request.getReader());
|
||||
assertEquals("Invalid request body", s, body);
|
||||
response.setStatus(HttpServletResponse.SC_CREATED);
|
||||
response.setHeader("Location", location);
|
||||
response.setContentLength(buf.length);
|
||||
response.setContentType(contentType.toString());
|
||||
FileCopyUtils.copy(buf, response.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class PutServlet extends HttpServlet {
|
||||
|
||||
private final String s;
|
||||
|
||||
|
||||
private final byte[] buf;
|
||||
|
||||
private final MediaType contentType;
|
||||
|
||||
private PutServlet(String s, byte[] buf, MediaType contentType) {
|
||||
this.s = s;
|
||||
this.buf = buf;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPut(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
assertTrue("Invalid request content-length", request.getContentLength() > 0);
|
||||
assertNotNull("No content-type", request.getContentType());
|
||||
String body = FileCopyUtils.copyToString(request.getReader());
|
||||
assertEquals("Invalid request body", s, body);
|
||||
response.setStatus(HttpServletResponse.SC_ACCEPTED);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class UriServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.getWriter().write(req.getRequestURI());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class MultipartServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
assertTrue(ServletFileUpload.isMultipartContent(req));
|
||||
FileItemFactory factory = new DiskFileItemFactory();
|
||||
ServletFileUpload upload = new ServletFileUpload(factory);
|
||||
try {
|
||||
List items = upload.parseRequest(req);
|
||||
assertEquals(4, items.size());
|
||||
FileItem item = (FileItem) items.get(0);
|
||||
assertTrue(item.isFormField());
|
||||
assertEquals("name 1", item.getFieldName());
|
||||
assertEquals("value 1", item.getString());
|
||||
|
||||
item = (FileItem) items.get(1);
|
||||
assertTrue(item.isFormField());
|
||||
assertEquals("name 2", item.getFieldName());
|
||||
assertEquals("value 2+1", item.getString());
|
||||
|
||||
item = (FileItem) items.get(2);
|
||||
assertTrue(item.isFormField());
|
||||
assertEquals("name 2", item.getFieldName());
|
||||
assertEquals("value 2+2", item.getString());
|
||||
|
||||
item = (FileItem) items.get(3);
|
||||
assertFalse(item.isFormField());
|
||||
assertEquals("logo", item.getFieldName());
|
||||
assertEquals("logo.jpg", item.getName());
|
||||
assertEquals("image/jpeg", item.getContentType());
|
||||
}
|
||||
catch (FileUploadException ex) {
|
||||
throw new ServletException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class DeleteServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
resp.setStatus(200);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.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.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
public class AsyncRestTemplateIntegrationTests extends AbstractJettyServerTestCase {
|
||||
|
||||
private AsyncRestTemplate template;
|
||||
|
||||
@Before
|
||||
public void createTemplate() {
|
||||
template = new AsyncRestTemplate(
|
||||
new HttpComponentsAsyncClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntity() throws ExecutionException, InterruptedException {
|
||||
Future<ResponseEntity<String>>
|
||||
futureEntity = template.getForEntity(baseUrl + "/{method}", String.class, "get");
|
||||
ResponseEntity<String> entity = futureEntity.get();
|
||||
assertEquals("Invalid content", helloWorld, entity.getBody());
|
||||
assertFalse("No headers", entity.getHeaders().isEmpty());
|
||||
assertEquals("Invalid content-type", contentType, entity.getHeaders().getContentType());
|
||||
assertEquals("Invalid status code", HttpStatus.OK, entity.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNoResponse() throws ExecutionException, InterruptedException {
|
||||
Future<ResponseEntity<String>>
|
||||
futureEntity = template.getForEntity(baseUrl + "/get/nothing", String.class);
|
||||
ResponseEntity<String> entity = futureEntity.get();
|
||||
assertNull("Invalid content", entity.getBody());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getNoContentTypeHeader()
|
||||
throws UnsupportedEncodingException, ExecutionException,
|
||||
InterruptedException {
|
||||
Future<ResponseEntity<byte[]>>
|
||||
futureEntity = template.getForEntity(baseUrl + "/get/nocontenttype",
|
||||
byte[].class);
|
||||
ResponseEntity<byte[]> responseEntity = futureEntity.get();
|
||||
assertArrayEquals("Invalid content", helloWorld.getBytes("UTF-8"),
|
||||
responseEntity.getBody());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getNoContent() throws ExecutionException, InterruptedException {
|
||||
Future<ResponseEntity<String>>
|
||||
responseFuture = template.getForEntity(baseUrl + "/status/nocontent", String.class);
|
||||
ResponseEntity<String> entity = responseFuture.get();
|
||||
assertEquals("Invalid response code", HttpStatus.NO_CONTENT, entity.getStatusCode());
|
||||
assertNull("Invalid content", entity.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNotModified() throws ExecutionException, InterruptedException {
|
||||
Future<ResponseEntity<String>>
|
||||
responseFuture = template.getForEntity(baseUrl + "/status/notmodified",
|
||||
String.class);
|
||||
ResponseEntity<String> entity = responseFuture.get();
|
||||
assertEquals("Invalid response code", HttpStatus.NOT_MODIFIED, entity.getStatusCode());
|
||||
assertNull("Invalid content", entity.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headForHeaders() throws ExecutionException, InterruptedException {
|
||||
Future<HttpHeaders> headersFuture = template.headForHeaders(baseUrl + "/get");
|
||||
HttpHeaders headers = headersFuture.get();
|
||||
assertTrue("No Content-Type header", headers.containsKey("Content-Type"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForLocation()
|
||||
throws URISyntaxException, ExecutionException, InterruptedException {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
Future<URI> locationFuture = template.postForLocation(baseUrl + "/{method}", requestEntity,
|
||||
"post");
|
||||
URI location = locationFuture.get();
|
||||
assertEquals("Invalid location", new URI(baseUrl + "/post/1"), location);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForLocationEntity()
|
||||
throws URISyntaxException, ExecutionException, InterruptedException {
|
||||
HttpHeaders entityHeaders = new HttpHeaders();
|
||||
entityHeaders.setContentType(new MediaType("text", "plain", Charset.forName("ISO-8859-15")));
|
||||
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, entityHeaders);
|
||||
Future<URI>
|
||||
locationFuture = template.postForLocation(baseUrl + "/{method}", entity,
|
||||
"post");
|
||||
URI location = locationFuture.get();
|
||||
assertEquals("Invalid location", new URI(baseUrl + "/post/1"), location);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForEntity()
|
||||
throws URISyntaxException, ExecutionException, InterruptedException {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
Future<ResponseEntity<String>>
|
||||
responseEntityFuture = template.postForEntity(baseUrl + "/{method}", requestEntity,
|
||||
String.class, "post");
|
||||
ResponseEntity<String> responseEntity = responseEntityFuture.get();
|
||||
assertEquals("Invalid content", helloWorld, responseEntity.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void put()
|
||||
throws URISyntaxException, ExecutionException, InterruptedException {
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld);
|
||||
Future<Void>
|
||||
responseEntityFuture = template.put(baseUrl + "/{method}", requestEntity,
|
||||
"put");
|
||||
responseEntityFuture.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete()
|
||||
throws URISyntaxException, ExecutionException, InterruptedException {
|
||||
Future<Void> deletedFuture = template.delete(new URI(baseUrl + "/delete"));
|
||||
deletedFuture.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notFound() throws ExecutionException, InterruptedException {
|
||||
try {
|
||||
Future<Void> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
|
||||
future.get();
|
||||
fail("HttpClientErrorException expected");
|
||||
}
|
||||
catch (HttpClientErrorException ex) {
|
||||
assertEquals(HttpStatus.NOT_FOUND, ex.getStatusCode());
|
||||
assertNotNull(ex.getStatusText());
|
||||
assertNotNull(ex.getResponseBodyAsString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverError() throws ExecutionException, InterruptedException {
|
||||
try {
|
||||
Future<Void> future = template.execute(baseUrl + "/status/server", HttpMethod.GET, null, null);
|
||||
future.get();
|
||||
fail("HttpServerErrorException expected");
|
||||
}
|
||||
catch (HttpServerErrorException ex) {
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, ex.getStatusCode());
|
||||
assertNotNull(ex.getStatusText());
|
||||
assertNotNull(ex.getResponseBodyAsString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsForAllow()
|
||||
throws URISyntaxException, ExecutionException, InterruptedException {
|
||||
Future<Set<HttpMethod>>
|
||||
allowedFuture = template.optionsForAllow(new URI(baseUrl + "/get"));
|
||||
Set<HttpMethod> allowed = allowedFuture.get();
|
||||
assertEquals("Invalid response",
|
||||
EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD, HttpMethod.TRACE), allowed);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
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();
|
||||
assertEquals("Invalid content", helloWorld, response.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exchangePost() throws Exception {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("MyHeader", "MyValue");
|
||||
requestHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
HttpEntity<String> requestEntity = new HttpEntity<String>(helloWorld, requestHeaders);
|
||||
Future<ResponseEntity<Void>>
|
||||
resultFuture = template.exchange(baseUrl + "/{method}", HttpMethod.POST,
|
||||
requestEntity, Void.class, "post");
|
||||
ResponseEntity<Void> result = resultFuture.get();
|
||||
assertEquals("Invalid location", new URI(baseUrl + "/post/1"),
|
||||
result.getHeaders().getLocation());
|
||||
assertFalse(result.hasBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipart() throws UnsupportedEncodingException, ExecutionException,
|
||||
InterruptedException {
|
||||
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
|
||||
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 + "/multipart", requestBody);
|
||||
future.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,54 +63,15 @@ import org.springframework.util.SocketUtils;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
public class RestTemplateIntegrationTests {
|
||||
public class RestTemplateIntegrationTests extends AbstractJettyServerTestCase {
|
||||
|
||||
private RestTemplate template;
|
||||
|
||||
private static Server jettyServer;
|
||||
|
||||
private static String helloWorld = "H\u00e9llo W\u00f6rld";
|
||||
|
||||
private static String baseUrl;
|
||||
|
||||
private static MediaType contentType;
|
||||
|
||||
@BeforeClass
|
||||
public static void startJettyServer() throws Exception {
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
jettyServer = new Server(port);
|
||||
baseUrl = "http://localhost:" + port;
|
||||
ServletContextHandler handler = new ServletContextHandler();
|
||||
byte[] bytes = helloWorld.getBytes("UTF-8");
|
||||
contentType = new MediaType("text", "plain", Collections.singletonMap("charset", "UTF-8"));
|
||||
handler.addServlet(new ServletHolder(new GetServlet(bytes, contentType)), "/get");
|
||||
handler.addServlet(new ServletHolder(new GetServlet(new byte[0], contentType)), "/get/nothing");
|
||||
handler.addServlet(new ServletHolder(new GetServlet(bytes, null)), "/get/nocontenttype");
|
||||
handler.addServlet(
|
||||
new ServletHolder(new PostServlet(helloWorld, baseUrl + "/post/1", bytes, contentType)),
|
||||
"/post");
|
||||
handler.addServlet(new ServletHolder(new StatusCodeServlet(204)), "/status/nocontent");
|
||||
handler.addServlet(new ServletHolder(new StatusCodeServlet(304)), "/status/notmodified");
|
||||
handler.addServlet(new ServletHolder(new ErrorServlet(404)), "/status/notfound");
|
||||
handler.addServlet(new ServletHolder(new ErrorServlet(500)), "/status/server");
|
||||
handler.addServlet(new ServletHolder(new UriServlet()), "/uri/*");
|
||||
handler.addServlet(new ServletHolder(new MultipartServlet()), "/multipart");
|
||||
jettyServer.setHandler(handler);
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTemplate() {
|
||||
template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopJettyServer() throws Exception {
|
||||
if (jettyServer != null) {
|
||||
jettyServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getString() {
|
||||
String s = template.getForObject(baseUrl + "/{method}", String.class, "get");
|
||||
@@ -258,142 +219,4 @@ public class RestTemplateIntegrationTests {
|
||||
assertFalse(result.hasBody());
|
||||
}
|
||||
|
||||
/** Servlet that sets the given status code. */
|
||||
@SuppressWarnings("serial")
|
||||
private static class StatusCodeServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
|
||||
private StatusCodeServlet(int sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
|
||||
((HttpServletResponse) response).setStatus(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/** Servlet that returns an error message for a given status code. */
|
||||
@SuppressWarnings("serial")
|
||||
private static class ErrorServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
|
||||
private ErrorServlet(int sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
|
||||
((HttpServletResponse) response).sendError(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class GetServlet extends HttpServlet {
|
||||
|
||||
private final byte[] buf;
|
||||
|
||||
private final MediaType contentType;
|
||||
|
||||
private GetServlet(byte[] buf, MediaType contentType) {
|
||||
this.buf = buf;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
if (contentType != null) {
|
||||
response.setContentType(contentType.toString());
|
||||
}
|
||||
response.setContentLength(buf.length);
|
||||
FileCopyUtils.copy(buf, response.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class PostServlet extends HttpServlet {
|
||||
|
||||
private final String s;
|
||||
|
||||
private final String location;
|
||||
|
||||
private final byte[] buf;
|
||||
|
||||
private final MediaType contentType;
|
||||
|
||||
private PostServlet(String s, String location, byte[] buf, MediaType contentType) {
|
||||
this.s = s;
|
||||
this.location = location;
|
||||
this.buf = buf;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
assertTrue("Invalid request content-length", request.getContentLength() > 0);
|
||||
assertNotNull("No content-type", request.getContentType());
|
||||
String body = FileCopyUtils.copyToString(request.getReader());
|
||||
assertEquals("Invalid request body", s, body);
|
||||
response.setStatus(HttpServletResponse.SC_CREATED);
|
||||
response.setHeader("Location", location);
|
||||
response.setContentLength(buf.length);
|
||||
response.setContentType(contentType.toString());
|
||||
FileCopyUtils.copy(buf, response.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class UriServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.getWriter().write(req.getRequestURI());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class MultipartServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
assertTrue(ServletFileUpload.isMultipartContent(req));
|
||||
FileItemFactory factory = new DiskFileItemFactory();
|
||||
ServletFileUpload upload = new ServletFileUpload(factory);
|
||||
try {
|
||||
List items = upload.parseRequest(req);
|
||||
assertEquals(4, items.size());
|
||||
FileItem item = (FileItem) items.get(0);
|
||||
assertTrue(item.isFormField());
|
||||
assertEquals("name 1", item.getFieldName());
|
||||
assertEquals("value 1", item.getString());
|
||||
|
||||
item = (FileItem) items.get(1);
|
||||
assertTrue(item.isFormField());
|
||||
assertEquals("name 2", item.getFieldName());
|
||||
assertEquals("value 2+1", item.getString());
|
||||
|
||||
item = (FileItem) items.get(2);
|
||||
assertTrue(item.isFormField());
|
||||
assertEquals("name 2", item.getFieldName());
|
||||
assertEquals("value 2+2", item.getString());
|
||||
|
||||
item = (FileItem) items.get(3);
|
||||
assertFalse(item.isFormField());
|
||||
assertEquals("logo", item.getFieldName());
|
||||
assertEquals("logo.jpg", item.getName());
|
||||
assertEquals("image/jpeg", item.getContentType());
|
||||
}
|
||||
catch (FileUploadException ex) {
|
||||
throw new ServletException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user