7 changed files with 371 additions and 2 deletions
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
/* |
||||
* Copyright 2002-2015 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.springframework.http.HttpRequest; |
||||
import org.springframework.util.concurrent.ListenableFuture; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* The execution context of asynchronous client http request. |
||||
* |
||||
* @author Jakub Narloch |
||||
* @see AsyncClientHttpRequestInterceptor |
||||
*/ |
||||
public interface AsyncClientHttpRequestExecution { |
||||
|
||||
/** |
||||
* Resumes the request execution by invoking 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 the future |
||||
* @throws IOException in case of I/O errors |
||||
*/ |
||||
ListenableFuture<ClientHttpResponse> executeAsync(HttpRequest request, byte[] body) throws IOException; |
||||
} |
||||
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
/* |
||||
* Copyright 2002-2015 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.springframework.http.HttpRequest; |
||||
import org.springframework.http.client.support.InterceptingAsyncHttpAccessor; |
||||
import org.springframework.util.concurrent.ListenableFuture; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* The asynchronous HTTP request interceptor. |
||||
* |
||||
* @author Jakub Narloch |
||||
* @see org.springframework.web.client.AsyncRestTemplate |
||||
* @see InterceptingAsyncHttpAccessor |
||||
*/ |
||||
public interface AsyncClientHttpRequestInterceptor { |
||||
|
||||
/** |
||||
* Intercepts the outgoing client HTTP request. |
||||
* |
||||
* @param request the request |
||||
* @param body the request's body |
||||
* @param execution the request execution context |
||||
* @return the future |
||||
* @throws IOException in case of I/O errors |
||||
*/ |
||||
ListenableFuture<ClientHttpResponse> interceptRequest( |
||||
HttpRequest request, byte[] body, AsyncClientHttpRequestExecution execution) throws IOException; |
||||
} |
||||
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
/* |
||||
* Copyright 2002-2015 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.springframework.http.HttpHeaders; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpRequest; |
||||
import org.springframework.util.StreamUtils; |
||||
import org.springframework.util.concurrent.ListenableFuture; |
||||
import org.springframework.util.concurrent.ListenableFutureAdapter; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.URI; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.concurrent.ExecutionException; |
||||
|
||||
/** |
||||
* A {@link AsyncClientHttpRequest} wrapper that enriches it proceeds the actual request execution with calling |
||||
* the registered interceptors. |
||||
* |
||||
* @author Jakub Narloch |
||||
* @see InterceptingAsyncClientHttpRequestFactory |
||||
*/ |
||||
class InterceptingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest { |
||||
|
||||
private AsyncClientHttpRequestFactory requestFactory; |
||||
|
||||
private List<AsyncClientHttpRequestInterceptor> interceptors; |
||||
|
||||
private URI uri; |
||||
|
||||
private HttpMethod httpMethod; |
||||
|
||||
/** |
||||
* Creates 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 httpMethod; |
||||
} |
||||
|
||||
@Override |
||||
public URI getURI() { |
||||
return uri; |
||||
} |
||||
|
||||
private class AsyncRequestExecution implements AsyncClientHttpRequestExecution { |
||||
|
||||
private Iterator<AsyncClientHttpRequestInterceptor> nextInterceptor = interceptors.iterator(); |
||||
|
||||
@Override |
||||
public ListenableFuture<ClientHttpResponse> executeAsync(HttpRequest request, byte[] body) throws IOException { |
||||
if (nextInterceptor.hasNext()) { |
||||
AsyncClientHttpRequestInterceptor interceptor = nextInterceptor.next(); |
||||
ListenableFuture<ClientHttpResponse> future = interceptor.interceptRequest(request, body, this); |
||||
return new IdentityListenableFutureAdapter<ClientHttpResponse>(future); |
||||
} |
||||
else { |
||||
AsyncClientHttpRequest req = requestFactory.createAsyncRequest(uri, httpMethod); |
||||
req.getHeaders().putAll(getHeaders()); |
||||
if (body.length > 0) { |
||||
StreamUtils.copy(body, req.getBody()); |
||||
} |
||||
return req.executeAsync(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static class IdentityListenableFutureAdapter<T> extends ListenableFutureAdapter<T, T> { |
||||
|
||||
protected IdentityListenableFutureAdapter(ListenableFuture<T> adaptee) { |
||||
super(adaptee); |
||||
} |
||||
|
||||
@Override |
||||
protected T adapt(T adapteeResult) throws ExecutionException { |
||||
return adapteeResult; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/* |
||||
* Copyright 2002-2015 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.springframework.http.HttpMethod; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.URI; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* The intercepting request factory. |
||||
* |
||||
* @author Jakub Narloch |
||||
* @see InterceptingAsyncClientHttpRequest |
||||
*/ |
||||
public class InterceptingAsyncClientHttpRequestFactory implements AsyncClientHttpRequestFactory { |
||||
|
||||
private AsyncClientHttpRequestFactory delegate; |
||||
|
||||
private List<AsyncClientHttpRequestInterceptor> interceptors; |
||||
|
||||
/** |
||||
* Creates new instance of {@link InterceptingAsyncClientHttpRequestFactory} with delegated request factory and |
||||
* list of interceptors. |
||||
* |
||||
* @param delegate the delegated request factory |
||||
* @param interceptors the list of interceptors. |
||||
*/ |
||||
public InterceptingAsyncClientHttpRequestFactory(AsyncClientHttpRequestFactory delegate, List<AsyncClientHttpRequestInterceptor> interceptors) { |
||||
|
||||
this.delegate = delegate; |
||||
this.interceptors = interceptors != null ? interceptors : Collections.<AsyncClientHttpRequestInterceptor>emptyList(); |
||||
} |
||||
|
||||
@Override |
||||
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException { |
||||
|
||||
return new InterceptingAsyncClientHttpRequest(delegate, interceptors, uri, httpMethod); |
||||
} |
||||
} |
||||
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
/* |
||||
* Copyright 2002-2015 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.support; |
||||
|
||||
import org.springframework.http.client.AsyncClientHttpRequestFactory; |
||||
import org.springframework.http.client.AsyncClientHttpRequestInterceptor; |
||||
import org.springframework.http.client.InterceptingAsyncClientHttpRequestFactory; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* The HTTP accessor that extends the base {@link AsyncHttpAccessor} with request intercepting functionality. |
||||
* |
||||
* @author Jakub Narloch |
||||
*/ |
||||
public abstract class InterceptingAsyncHttpAccessor extends AsyncHttpAccessor { |
||||
|
||||
private List<AsyncClientHttpRequestInterceptor> interceptors = new ArrayList<AsyncClientHttpRequestInterceptor>(); |
||||
|
||||
/** |
||||
* Retrieves the list of interceptors. |
||||
* |
||||
* @return the list of interceptors |
||||
*/ |
||||
public List<AsyncClientHttpRequestInterceptor> getInterceptors() { |
||||
return interceptors; |
||||
} |
||||
|
||||
/** |
||||
* Sets the list of interceptors. |
||||
* |
||||
* @param interceptors the list of interceptors |
||||
*/ |
||||
public void setInterceptors(List<AsyncClientHttpRequestInterceptor> interceptors) { |
||||
this.interceptors = interceptors; |
||||
} |
||||
|
||||
@Override |
||||
public AsyncClientHttpRequestFactory getAsyncRequestFactory() { |
||||
AsyncClientHttpRequestFactory asyncRequestFactory = super.getAsyncRequestFactory(); |
||||
if(interceptors.isEmpty()) { |
||||
return asyncRequestFactory; |
||||
} |
||||
return new InterceptingAsyncClientHttpRequestFactory(asyncRequestFactory, getInterceptors()); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue