diff options
6 files changed, 292 insertions, 9 deletions
| diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafHttpRequestRetryHandler.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafHttpRequestRetryHandler.java new file mode 100644 index 00000000..3aa908e8 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafHttpRequestRetryHandler.java @@ -0,0 +1,33 @@ +package at.gv.egiz.eaaf.core.impl.http; + +import java.net.UnknownHostException; +import java.util.Arrays; + +import javax.net.ssl.SSLException; + +import org.apache.http.client.HttpRequestRetryHandler; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; + +public class EaafHttpRequestRetryHandler extends DefaultHttpRequestRetryHandler implements +    HttpRequestRetryHandler { +    +  /** +   * Create the request retry handler using the following list of non-retriable. +   * IOException classes: <br> +   * <ul> +   * <li>UnknownHostException</li> +   * <li>SSLException</li> +   * </ul> +   *  +   * @param retryCount              how many times to retry; 0 means no retries +   * @param requestSentRetryEnabled true if it's OK to retry non-idempotent +   *                                requests that have been sent +   */ +  public EaafHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled) { +    super(retryCount, requestSentRetryEnabled, Arrays.asList( +        UnknownHostException.class, +        SSLException.class)); +       +  } +   +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java index 6a66dfff..ec7d115a 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java @@ -56,7 +56,13 @@ public class HttpClientConfiguration {    @Setter    private boolean followHttpRedirects = true; - +   +  @Setter +  private int httpErrorRetryCount = 3; +   +  @Setter +  private boolean httpErrorRetryPost = false; +      /**     * Get a new HTTP-client configuration object.     * diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java index 4e811eaa..b53226ce 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java @@ -65,7 +65,11 @@ public class HttpClientFactory implements IHttpClientFactory {    public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION =        "client.http.connection.timeout.connection";    public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = -      "client.http.connection.timeout.request"; +      "client.http.connection.timeout.request";   +  public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT =  +      "client.http.connection.retry.count"; +  public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST =  +      "client.http.connection.retry.post";    public static final String PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL =        "client.http.ssl.hostnameverifier.trustall"; @@ -91,7 +95,9 @@ public class HttpClientFactory implements IHttpClientFactory {    public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = "30";    public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL = "500";    public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = "100"; - +  public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT = "3"; +  public static final String DEFAUTL_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST = String.valueOf(false); +      private String defaultConfigurationId = null;    private final Map<String, HttpClientBuilder> availableBuilders = new HashMap<>(); @@ -127,8 +133,11 @@ public class HttpClientFactory implements IHttpClientFactory {        config.validate();        builder = HttpClients.custom(); +             +      //inject request configuration        builder.setDefaultRequestConfig(buildDefaultRequestConfig()); - +      injectInternalRetryHandler(builder, config); +              //inject basic authentication infos        injectBasicAuthenticationIfRequired(builder, config); @@ -147,6 +156,22 @@ public class HttpClientFactory implements IHttpClientFactory {    } +  private void injectInternalRetryHandler(HttpClientBuilder builder, HttpClientConfiguration config) {     +    if (config.getHttpErrorRetryCount() > 0) { +      log.info("Set HTTP error-retry to {} for http-client: {}",  +          config.getHttpErrorRetryCount(), config.getFriendlyName()); +      builder.setRetryHandler(new EaafHttpRequestRetryHandler( +          config.getHttpErrorRetryCount(),  +          config.isHttpErrorRetryPost()));   +       +    } else { +      log.info("Disable HTTP error-retry for http-client: {}", config.getFriendlyName()); +      builder.disableAutomaticRetries(); +       +    } +     +  } +    @PostConstruct    private void initalize() throws EaafException {      final HttpClientConfiguration defaultHttpClientConfig = buildDefaultHttpClientConfiguration(); @@ -157,7 +182,8 @@ public class HttpClientFactory implements IHttpClientFactory {      // set default request configuration      defaultHttpClientBuilder.setDefaultRequestConfig(buildDefaultRequestConfig()); - +    injectInternalRetryHandler(defaultHttpClientBuilder, defaultHttpClientConfig); +          //inject http basic authentication      injectBasicAuthenticationIfRequired(defaultHttpClientBuilder, defaultHttpClientConfig); @@ -205,6 +231,14 @@ public class HttpClientFactory implements IHttpClientFactory {      config.setDisableHostnameValidation(basicConfig.getBasicConfigurationBoolean(          PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL, false)); +    config.setHttpErrorRetryCount(Integer.parseInt(basicConfig.getBasicConfiguration( +        PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT,  +        DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT))); +    config.setHttpErrorRetryPost(Boolean.parseBoolean(basicConfig.getBasicConfiguration( +        PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST,  +        DEFAUTL_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST))); +     +          // validate configuration object      config.validate(); @@ -324,7 +358,7 @@ public class HttpClientFactory implements IHttpClientFactory {              .setSocketTimeout(Integer.parseInt(                  basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET,                      DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET)) -                * 1000)    +                * 1000)              .build();      return requestConfig; diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java index 7ec58d46..4e8374e1 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java @@ -2,10 +2,10 @@ package at.gv.egiz.eaaf.core.impl.http;  import javax.annotation.Nonnull; -import at.gv.egiz.eaaf.core.exceptions.EaafException; -  import org.apache.http.impl.client.CloseableHttpClient; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +  public interface IHttpClientFactory {    /** diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java index 72ec7008..63ac38a3 100644 --- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java @@ -3,6 +3,7 @@ package at.gv.egiz.eaaf.core.test.http;  import java.io.IOException;  import java.net.HttpURLConnection;  import java.net.InetAddress; +import java.net.SocketTimeoutException;  import java.security.KeyStore;  import java.security.KeyStoreException;  import java.security.Provider; @@ -12,6 +13,7 @@ import org.apache.commons.lang3.RandomStringUtils;  import org.apache.http.client.ClientProtocolException;  import org.apache.http.client.methods.CloseableHttpResponse;  import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost;  import org.apache.http.client.methods.HttpUriRequest;  import org.apache.http.impl.client.CloseableHttpClient;  import org.junit.After; @@ -32,6 +34,7 @@ import okhttp3.HttpUrl;  import okhttp3.mockwebserver.MockResponse;  import okhttp3.mockwebserver.MockWebServer;  import okhttp3.mockwebserver.RecordedRequest; +import okhttp3.mockwebserver.SocketPolicy;  import okhttp3.tls.HandshakeCertificates;  import okhttp3.tls.HeldCertificate; @@ -84,6 +87,27 @@ public class HttpClientFactoryTest {    }    @Test +  public void defaultHttpClientRetryOneTime() throws EaafException, InterruptedException,  +      ClientProtocolException, IOException {     +    CloseableHttpClient client = httpClientFactory.getHttpClient(); +    Assert.assertNotNull("No httpClient", client); +     +    mockWebServer = new MockWebServer(); +    mockServerUrl = mockWebServer.url("/sp/junit"); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));        +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody("GetData")); + +    //request webservice +    final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString()); +    final CloseableHttpResponse httpResp1 = client.execute(httpGet1);     +    Assert.assertEquals("http statusCode", 200, httpResp1.getStatusLine().getStatusCode()); +         +  } +   +  @Test    public void getCustomClientsDefault() throws EaafException {      final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");      Assert.assertFalse("Wrong default config - Hostnamevalidation", @@ -157,6 +181,187 @@ public class HttpClientFactoryTest {    }    @Test +  public void httpPostRetryNotAllowed() throws EaafException, InterruptedException,  +      ClientProtocolException, IOException { +    final HttpClientConfiguration config =  +        new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3)); +    config.setHttpErrorRetryCount(2); +    config.setHttpErrorRetryPost(false); +     +    CloseableHttpClient client = httpClientFactory.getHttpClient(config); +    Assert.assertNotNull("No httpClient", client); +     +     +    mockWebServer = new MockWebServer(); +    mockServerUrl = mockWebServer.url("/sp/junit"); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));        +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody("GetData")); + +    //request webservice +    final HttpUriRequest httpGet1 = new HttpPost(mockServerUrl.url().toString()); +    try { +      client.execute(httpGet1);     +      Assert.fail("HTTP POST retry not allowed"); +       +    } catch (SocketTimeoutException e) { +      Assert.assertNotNull("No errorMsg", e.getMessage()); +       +    } +     +  } +   +  @Test +  public void httpPostRetryOneTime() throws EaafException, InterruptedException,  +      ClientProtocolException, IOException { +    final HttpClientConfiguration config =  +        new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3)); +    config.setHttpErrorRetryCount(2); +    config.setHttpErrorRetryPost(true); +     +    CloseableHttpClient client = httpClientFactory.getHttpClient(config); +    Assert.assertNotNull("No httpClient", client); +     +     +    mockWebServer = new MockWebServer(); +    mockServerUrl = mockWebServer.url("/sp/junit"); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));        +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody("GetData")); + +    //request webservice +    final HttpUriRequest httpGet1 = new HttpPost(mockServerUrl.url().toString()); +    final CloseableHttpResponse httpResp1 = client.execute(httpGet1);     +    Assert.assertEquals("http statusCode", 200, httpResp1.getStatusLine().getStatusCode()); +         +  } +   +  @Test +  public void testHttpClientRetryOneTime() throws EaafException, InterruptedException,  +      ClientProtocolException, IOException { +    final HttpClientConfiguration config =  +        new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3)); +    config.setHttpErrorRetryCount(2); +     +    CloseableHttpClient client = httpClientFactory.getHttpClient(config); +    Assert.assertNotNull("No httpClient", client); +     +     +    mockWebServer = new MockWebServer(); +    mockServerUrl = mockWebServer.url("/sp/junit"); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));        +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody("GetData")); + +    //request webservice +    final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString()); +    final CloseableHttpResponse httpResp1 = client.execute(httpGet1);     +    Assert.assertEquals("http statusCode", 200, httpResp1.getStatusLine().getStatusCode()); +         +  } +   +  @Test +  public void testHttpClientRetryTwoTime() throws EaafException, InterruptedException,  +      ClientProtocolException, IOException { +    final HttpClientConfiguration config =  +        new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3)); +    config.setHttpErrorRetryCount(2); +     +    CloseableHttpClient client = httpClientFactory.getHttpClient(config); +    Assert.assertNotNull("No httpClient", client); +     +     +    mockWebServer = new MockWebServer(); +    mockServerUrl = mockWebServer.url("/sp/junit"); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));        +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)); +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody("GetData")); + +    //request webservice +    final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString()); +    final CloseableHttpResponse httpResp1 = client.execute(httpGet1);     +    Assert.assertEquals("http statusCode", 200, httpResp1.getStatusLine().getStatusCode()); +     +  } +   +  @Test +  public void testHttpClientRetryMaxReached() throws EaafException, InterruptedException,  +      ClientProtocolException, IOException { +    final HttpClientConfiguration config =  +        new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3)); +    config.setHttpErrorRetryCount(2); +     +    CloseableHttpClient client = httpClientFactory.getHttpClient(config); +    Assert.assertNotNull("No httpClient", client); +         +    mockWebServer = new MockWebServer(); +    mockServerUrl = mockWebServer.url("/sp/junit"); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));        +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)); +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody("GetData")); + +    //request webservice +    final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString()); +    try { +      client.execute(httpGet1);     +      Assert.fail("Max retry failed"); +       +    } catch (SocketTimeoutException e) { +      Assert.assertNotNull("No errorMsg", e.getMessage()); +       +    }         +  } +   +  @Test +  public void testHttpClientNoRetry() throws EaafException, InterruptedException,  +      ClientProtocolException, IOException { +    final HttpClientConfiguration config =  +        new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3)); +    config.setHttpErrorRetryCount(0); +     +    CloseableHttpClient client = httpClientFactory.getHttpClient(config); +    Assert.assertNotNull("No httpClient", client); +         +    mockWebServer = new MockWebServer(); +    mockServerUrl = mockWebServer.url("/sp/junit"); +    mockWebServer.enqueue(new MockResponse() +        .setSocketPolicy(SocketPolicy.NO_RESPONSE) +        .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));        +    mockWebServer.enqueue(new MockResponse().setResponseCode(200) +        .setBody("GetData")); + +    //request webservice +    final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString()); +    try { +      client.execute(httpGet1);     +      Assert.fail("Max retry failed"); +       +    } catch (SocketTimeoutException e) { +      Assert.assertNotNull("No errorMsg", e.getMessage()); +       +    }         +  } +   +  @Test    public void getCustomClientBasicAuthNoPassword() throws EaafException {      final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");      config.setAuthMode("password"); @@ -370,4 +575,5 @@ public class HttpClientFactoryTest {      Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());    } +    } diff --git a/eaaf_core_utils/src/test/resources/data/config1.properties b/eaaf_core_utils/src/test/resources/data/config1.properties index 25bd201f..93729b15 100644 --- a/eaaf_core_utils/src/test/resources/data/config1.properties +++ b/eaaf_core_utils/src/test/resources/data/config1.properties @@ -2,4 +2,8 @@ security.hsmfacade.host=eid.a-sit.at  security.hsmfacade.port=9050  security.hsmfacade.trustedsslcert=src/test/resources/data/hsm_facade_trust_root.crt  security.hsmfacade.username=authhandler-junit -security.hsmfacade.password=supersecret123
\ No newline at end of file +security.hsmfacade.password=supersecret123 + +client.http.connection.timeout.socket=1 +client.http.connection.timeout.connection=1 +client.http.connection.timeout.request=1
\ No newline at end of file | 
