ref #8812 setting NoConnectionReuseStrategy for PoolingHttpClientConnectionManager...
[taxeditor.git] / eu.etaxonomy.taxeditor.cdmlib / src / main / java / eu / etaxonomy / taxeditor / service / TimestampingHttpInvokerRequestExecutor.java
1 /**
2 * Copyright (C) 2020 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.taxeditor.service;
10
11 import java.io.IOException;
12 import java.net.URI;
13 import java.time.LocalDateTime;
14 import java.time.format.DateTimeFormatter;
15
16 import org.apache.http.Header;
17 import org.apache.http.HttpResponse;
18 import org.apache.http.client.HttpClient;
19 import org.apache.http.client.methods.HttpPost;
20 import org.apache.http.config.Registry;
21 import org.apache.http.config.RegistryBuilder;
22 import org.apache.http.conn.socket.ConnectionSocketFactory;
23 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
24 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
25 import org.apache.http.impl.NoConnectionReuseStrategy;
26 import org.apache.http.impl.client.HttpClientBuilder;
27 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
28 import org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor;
29 import org.springframework.remoting.httpinvoker.HttpInvokerClientConfiguration;
30
31 import eu.etaxonomy.taxeditor.remoting.RemoteExecutionTimestampsUtil;
32
33 /**
34 * HttpInvokerRequestExecutor which extends the {@link HttpComponentsHttpInvokerRequestExecutor} by two functionalities:
35 *
36 * <ol>
37 * <li>Records time stamps when sending the request and when receiving the response.</li>
38 * <li>Allows custom configuration of the {@link PoolingHttpClientConnectionManager}
39 * (see <a href="https://dev.e-taxonomy.eu/redmine/issues/8812">https://dev.e-taxonomy.eu/redmine/issues/8812</a>).
40 * </ol>
41 *
42 * @author a.kohlbecker
43 * @since Jan 17, 2020
44 */
45 public class TimestampingHttpInvokerRequestExecutor extends HttpComponentsHttpInvokerRequestExecutor {
46
47 private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 100;
48
49 private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
50
51 /**
52 * Default in PoolingHttpClientConnectionManager is 2000 milliseconds.
53 *
54 * see https://stackoverflow.com/questions/10558791/apache-httpclient-interim-error-nohttpresponseexception
55 */
56 private static final int VALIDATE_AFTER_INACTIVITY = 2000;
57
58 public TimestampingHttpInvokerRequestExecutor() {
59 super(createDefaultHttpClient());
60 }
61
62
63 @Override
64 protected HttpResponse executeHttpPost(HttpInvokerClientConfiguration config, HttpClient httpClient,
65 HttpPost httpPost) throws IOException {
66
67
68 setExecutionRequestClientTimestamp(httpPost.getURI());
69
70 HttpResponse respone = super.executeHttpPost(config, httpClient, httpPost);
71
72 setExecutionResponseHttpHeaderTimestamp(respone);
73
74 return respone;
75 }
76
77 private void setExecutionRequestClientTimestamp(URI requestURI){
78
79 LocalDateTime date = LocalDateTime.now();
80 String dateTimeStr = date.format(DateTimeFormatter.ISO_DATE_TIME);
81 RemoteExecutionTimestampsUtil.setLastRequestClientTime(dateTimeStr);
82 if(requestURI != null){
83 RemoteExecutionTimestampsUtil.setLastServiceMethod(requestURI.toString());
84 }
85
86 }
87
88 private void setExecutionResponseHttpHeaderTimestamp(HttpResponse respone){
89 Header dateHeader = respone.getFirstHeader("Date");
90 if(dateHeader != null){
91 RemoteExecutionTimestampsUtil.setLastResponseHttpHeaderTime(dateHeader.getValue());
92 }
93 }
94
95 private static HttpClient createDefaultHttpClient() {
96 Registry<ConnectionSocketFactory> schemeRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
97 .register("http", PlainConnectionSocketFactory.getSocketFactory())
98 .register("https", SSLConnectionSocketFactory.getSocketFactory())
99 .build();
100
101 PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(schemeRegistry);
102 connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
103 connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);
104 connectionManager.setValidateAfterInactivity(VALIDATE_AFTER_INACTIVITY);
105
106 return HttpClientBuilder.create()
107 .setConnectionManager(connectionManager)
108 .setConnectionReuseStrategy(new NoConnectionReuseStrategy()) // see #8812
109 .build();
110 }
111
112 }