1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.transport.http;
18
19 import java.io.IOException;
20 import java.net.URI;
21 import java.net.URISyntaxException;
22 import java.util.Map;
23
24 import org.apache.http.HttpEntityEnclosingRequest;
25 import org.apache.http.HttpException;
26 import org.apache.http.HttpHost;
27 import org.apache.http.HttpRequest;
28 import org.apache.http.HttpRequestInterceptor;
29 import org.apache.http.auth.AuthScope;
30 import org.apache.http.auth.Credentials;
31 import org.apache.http.auth.UsernamePasswordCredentials;
32 import org.apache.http.client.HttpClient;
33 import org.apache.http.client.methods.HttpPost;
34 import org.apache.http.conn.ClientConnectionManager;
35 import org.apache.http.conn.routing.HttpRoute;
36 import org.apache.http.impl.client.DefaultHttpClient;
37 import org.apache.http.impl.conn.PoolingClientConnectionManager;
38 import org.apache.http.params.HttpConnectionParams;
39 import org.apache.http.protocol.HTTP;
40 import org.apache.http.protocol.HttpContext;
41
42 import org.springframework.beans.factory.DisposableBean;
43 import org.springframework.beans.factory.InitializingBean;
44 import org.springframework.util.Assert;
45 import org.springframework.ws.transport.WebServiceConnection;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class HttpComponentsMessageSender extends AbstractHttpWebServiceMessageSender
62 implements InitializingBean, DisposableBean {
63
64 private static final int DEFAULT_CONNECTION_TIMEOUT_MILLISECONDS = (60 * 1000);
65
66 private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);
67
68 private HttpClient httpClient;
69
70 private Credentials credentials;
71
72 private AuthScope authScope = AuthScope.ANY;
73
74
75
76
77
78 public HttpComponentsMessageSender() {
79 DefaultHttpClient defaultClient = new DefaultHttpClient(new PoolingClientConnectionManager());
80 defaultClient.addRequestInterceptor(new RemoveSoapHeadersInterceptor(), 0);
81
82 this.httpClient = defaultClient;
83 setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT_MILLISECONDS);
84 setReadTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS);
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98 public HttpComponentsMessageSender(HttpClient httpClient) {
99 Assert.notNull(httpClient, "httpClient must not be null");
100 this.httpClient = httpClient;
101 }
102
103
104
105
106
107
108
109 public void setCredentials(Credentials credentials) {
110 this.credentials = credentials;
111 }
112
113
114
115
116 public HttpClient getHttpClient() {
117 return httpClient;
118 }
119
120
121
122
123 public void setHttpClient(HttpClient httpClient) {
124 this.httpClient = httpClient;
125 }
126
127
128
129
130
131
132
133 public void setConnectionTimeout(int timeout) {
134 if (timeout < 0) {
135 throw new IllegalArgumentException("timeout must be a non-negative value");
136 }
137 HttpConnectionParams.setConnectionTimeout(getHttpClient().getParams(), timeout);
138 }
139
140
141
142
143
144
145
146 public void setReadTimeout(int timeout) {
147 if (timeout < 0) {
148 throw new IllegalArgumentException("timeout must be a non-negative value");
149 }
150 HttpConnectionParams.setSoTimeout(getHttpClient().getParams(), timeout);
151 }
152
153
154
155
156
157
158
159 public void setMaxTotalConnections(int maxTotalConnections) {
160 if (maxTotalConnections <= 0) {
161 throw new IllegalArgumentException("maxTotalConnections must be a positive value");
162 }
163 ClientConnectionManager connectionManager = getHttpClient().getConnectionManager();
164 if (!(connectionManager instanceof PoolingClientConnectionManager)) {
165 throw new IllegalArgumentException("maxTotalConnections is not supported on " +
166 connectionManager.getClass().getName() + ". Use " + PoolingClientConnectionManager.class.getName() +
167 " instead");
168 }
169 ((PoolingClientConnectionManager) connectionManager).setMaxTotal(maxTotalConnections);
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 public void setMaxConnectionsPerHost(Map<String, String> maxConnectionsPerHost) throws URISyntaxException {
188 ClientConnectionManager connectionManager = getHttpClient().getConnectionManager();
189 if (!(connectionManager instanceof PoolingClientConnectionManager)) {
190 throw new IllegalArgumentException("maxConnectionsPerHost is not supported on " +
191 connectionManager.getClass().getName() + ". Use " + PoolingClientConnectionManager.class.getName() +
192 " instead");
193 }
194 PoolingClientConnectionManager poolingConnectionManager =
195 (PoolingClientConnectionManager) connectionManager;
196
197 for (Map.Entry<String, String> entry : maxConnectionsPerHost.entrySet()) {
198 URI uri = new URI(entry.getKey());
199 HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
200 HttpRoute route = new HttpRoute(host);
201
202 int max = Integer.parseInt(entry.getValue());
203
204 poolingConnectionManager.setMaxPerRoute(route, max);
205 }
206 }
207
208
209
210
211
212
213
214
215 public void setAuthScope(AuthScope authScope) {
216 this.authScope = authScope;
217 }
218
219 public void afterPropertiesSet() throws Exception {
220 if (credentials != null && getHttpClient() instanceof DefaultHttpClient) {
221 ((DefaultHttpClient) getHttpClient()).getCredentialsProvider().setCredentials(authScope, credentials);
222 }
223 }
224
225 public WebServiceConnection createConnection(URI uri) throws IOException {
226 HttpPost httpPost = new HttpPost(uri);
227 if (isAcceptGzipEncoding()) {
228 httpPost.addHeader(HttpTransportConstants.HEADER_ACCEPT_ENCODING,
229 HttpTransportConstants.CONTENT_ENCODING_GZIP);
230 }
231 HttpContext httpContext = createContext(uri);
232 return new HttpComponentsConnection(getHttpClient(), httpPost, httpContext);
233 }
234
235
236
237
238
239
240
241
242 protected HttpContext createContext(URI uri) {
243 return null;
244 }
245
246 public void destroy() throws Exception {
247 getHttpClient().getConnectionManager().shutdown();
248 }
249
250
251
252
253
254
255 public static class RemoveSoapHeadersInterceptor implements HttpRequestInterceptor {
256
257 public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
258 if (request instanceof HttpEntityEnclosingRequest) {
259 if (request.containsHeader(HTTP.TRANSFER_ENCODING)) {
260 request.removeHeaders(HTTP.TRANSFER_ENCODING);
261 }
262 if (request.containsHeader(HTTP.CONTENT_LEN)) {
263 request.removeHeaders(HTTP.CONTENT_LEN);
264 }
265 }
266 }
267 }
268 }