diff --git a/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingHttpRequestFactory.java b/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingHttpRequestFactory.java index 3c3736373e..737633d620 100644 --- a/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingHttpRequestFactory.java +++ b/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingHttpRequestFactory.java @@ -14,7 +14,7 @@ * This request factory will attempt to load resources using {@link * org.mapfish.print.config.Configuration#loadFile(String)} and {@link * org.mapfish.print.config.Configuration#isAccessible(String)} to load the resources if the http - * method is GET and will fallback to the normal/wrapped factory to make http requests. + * method is GET and will fall back to the normal/wrapped factory to make http requests. */ public final class ConfigFileResolvingHttpRequestFactory implements MfClientHttpRequestFactory { private final Configuration config; @@ -22,6 +22,7 @@ public final class ConfigFileResolvingHttpRequestFactory implements MfClientHttp private final MfClientHttpRequestFactoryImpl httpRequestFactory; private final List callbacks = new CopyOnWriteArrayList<>(); + /** Maximum number of attempts to try to fetch the same http request in case it is failing. */ @Value("${httpRequest.fetchRetry.maxNumber}") private int httpRequestMaxNumberFetchRetry; @@ -54,7 +55,9 @@ public void register(@Nonnull final RequestConfigurator callback) { } @Override - public ClientHttpRequest createRequest(final URI uri, final HttpMethod httpMethod) { + @Nonnull + public ClientHttpRequest createRequest( + @Nonnull final URI uri, @Nonnull final HttpMethod httpMethod) { return new ConfigFileResolvingRequest(this, uri, httpMethod); } diff --git a/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingRequest.java b/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingRequest.java index 59874de66a..a1ae107db2 100644 --- a/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingRequest.java +++ b/core/src/main/java/org/mapfish/print/http/ConfigFileResolvingRequest.java @@ -141,16 +141,28 @@ private ClientHttpResponse doFileRequest() throws IOException { } private ClientHttpResponse doHttpRequestWithRetry(final HttpHeaders headers) throws IOException { - AtomicInteger counter = new AtomicInteger(); + final AtomicInteger counter = new AtomicInteger(); do { logFetchingURIResource(headers); try { - ClientHttpResponse response = attemptToFetchResponse(headers, counter); + ClientHttpResponse response = attemptToFetchResponse(headers); if (response != null) { return response; + } else { + if (canRetry(counter)) { + sleepWithExceptionHandling(); + LOGGER.debug("Retry fetching {}", this.getURI()); + } else { + PrintException printException = new PrintException("Failed fetching " + getURI()); + LOGGER.debug("Throwing exception since it cannot retry.", printException); + throw printException; + } + } + } catch (final IOException | RuntimeException e) { + boolean hasSlept = sleepIfPossible(e, counter); + if (!hasSlept) { + throw e; } - } catch (final IOException e) { - handleIOException(e, counter); } } while (true); } @@ -158,56 +170,54 @@ private ClientHttpResponse doHttpRequestWithRetry(final HttpHeaders headers) thr private void logFetchingURIResource(final HttpHeaders headers) { // Display headers, one by line : LOGGER.debug( - "Fetching URI resource {}, headers:\n{}", + "Fetching {}, using headers:\n{}", this.getURI(), headers.entrySet().stream() .map(entry -> entry.getKey() + "=" + String.join(", ", entry.getValue())) .collect(Collectors.joining("\n"))); } - private ClientHttpResponse attemptToFetchResponse( - final HttpHeaders headers, final AtomicInteger counter) throws IOException { + private ClientHttpResponse attemptToFetchResponse(final HttpHeaders headers) throws IOException { ClientHttpRequest requestUsed = this.request != null ? this.request : createRequestFromWrapped(headers); LOGGER.debug("Executing http request: {}", requestUsed.getURI()); ClientHttpResponse response = executeCallbacksAndRequest(requestUsed); - if (response.getRawStatusCode() < 500) { - LOGGER.debug( - "Fetching success URI resource {}, status code {}", - getURI(), - response.getRawStatusCode()); - return response; - } - LOGGER.debug( - "Fetching failed URI resource {}, error code {}", getURI(), response.getRawStatusCode()); - if (canRetry(counter)) { - sleepWithExceptionHandling(); - LOGGER.debug("Retry fetching URI resource {}", this.getURI()); - } else { - throw new PrintException( - String.format( - "Fetching failed URI resource %s, error code %s", - getURI(), response.getRawStatusCode())); + final int minStatusCodeError = HttpStatus.INTERNAL_SERVER_ERROR.value(); + int rawStatusCode = minStatusCodeError; + try { + rawStatusCode = response.getRawStatusCode(); + if (rawStatusCode < minStatusCodeError) { + LOGGER.debug("Successfully fetched {}, with status code {}", getURI(), rawStatusCode); + return response; + } + LOGGER.debug("Failed fetching {}, with error code {}", getURI(), rawStatusCode); + return null; + } finally { + if (rawStatusCode >= minStatusCodeError) { + response.close(); + } } - return null; } - private void handleIOException(final IOException e, final AtomicInteger counter) - throws IOException { - + private boolean sleepIfPossible(final Exception e, final AtomicInteger counter) { if (canRetry(counter)) { sleepWithExceptionHandling(); - LOGGER.debug("Retry fetching URI resource {}", this.getURI()); + LOGGER.debug("Retry fetching {} following exception", this.getURI(), e); + return true; } else { - LOGGER.debug("Fetching failed URI resource {}", getURI()); - throw e; + LOGGER.debug( + "Reached maximum number of {} allowed requests attempts for {}", + getHttpRequestMaxNumberFetchRetry(), + getURI()); + return false; } } private void sleepWithExceptionHandling() { + int sleepMs = configFileResolvingHttpRequestFactory.getHttpRequestFetchRetryIntervalMillis(); + LOGGER.debug("Sleeping {} ms before retrying.", sleepMs); try { - TimeUnit.MILLISECONDS.sleep( - configFileResolvingHttpRequestFactory.getHttpRequestFetchRetryIntervalMillis()); + TimeUnit.MILLISECONDS.sleep(sleepMs); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new PrintException("Interrupted while sleeping", e); diff --git a/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java b/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java index d8f1827fbc..51a81325f9 100644 --- a/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java +++ b/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java @@ -87,18 +87,22 @@ private CachedClientHttpResponse(final ClientHttpResponse originalResponse) thro this.headers = originalResponse.getHeaders(); this.status = originalResponse.getRawStatusCode(); this.statusText = originalResponse.getStatusText(); - this.cachedFile = + this.cachedFile = createCachedFile(originalResponse.getBody()); + } + + private File createCachedFile(final InputStream originalBody) throws IOException { + File tempFile = File.createTempFile("cacheduri", null, HttpRequestFetcher.this.temporaryDirectory); - LOGGER.debug("Caching URI resource to {}", this.cachedFile); - try (OutputStream os = Files.newOutputStream(this.cachedFile.toPath())) { - InputStream body = originalResponse.getBody(); + LOGGER.debug("Caching URI resource to {}", tempFile); + try (OutputStream os = Files.newOutputStream(tempFile.toPath())) { LOGGER.debug( - "Get from input stream {}, for response {}, body available: {}", - body.getClass(), - originalResponse.getClass(), - body.available()); - IOUtils.copy(body, os); + "Get from input stream {}, body available: {}", + originalBody.getClass(), + originalBody.available()); + IOUtils.copy(originalBody, os); + originalBody.close(); } + return tempFile; } @Override diff --git a/core/src/main/java/org/mapfish/print/http/MfClientHttpRequestFactoryImpl.java b/core/src/main/java/org/mapfish/print/http/MfClientHttpRequestFactoryImpl.java index dc6767edc4..0cbafd288f 100644 --- a/core/src/main/java/org/mapfish/print/http/MfClientHttpRequestFactoryImpl.java +++ b/core/src/main/java/org/mapfish/print/http/MfClientHttpRequestFactoryImpl.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -31,6 +32,7 @@ import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import org.mapfish.print.config.Configuration; +import org.mapfish.print.servlet.job.impl.ThreadPoolJobManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; @@ -52,8 +54,11 @@ public class MfClientHttpRequestFactoryImpl extends HttpComponentsClientHttpRequ * @param maxConnTotal Maximum total connections. * @param maxConnPerRoute Maximum connections per route. */ - public MfClientHttpRequestFactoryImpl(final int maxConnTotal, final int maxConnPerRoute) { - super(createHttpClient(maxConnTotal, maxConnPerRoute)); + public MfClientHttpRequestFactoryImpl( + final int maxConnTotal, + final int maxConnPerRoute, + final ThreadPoolJobManager threadPoolJobManager) { + super(createHttpClient(maxConnTotal, maxConnPerRoute, threadPoolJobManager)); } @Nullable @@ -61,21 +66,41 @@ static Configuration getCurrentConfiguration() { return CURRENT_CONFIGURATION.get(); } - private static int getIntProperty(final String name) { + /** + * Return the number of milliseconds until the timeout Use the Automatic cancellation timeout if + * not defined. + * + * @param name timeout idemtifier + * @return the number of milliseconds until the timeout + */ + private static int getTimeoutValue( + final String name, final ThreadPoolJobManager threadPoolJobManager) { final String value = System.getProperty(name); if (value == null) { - return -1; + long millis = TimeUnit.SECONDS.toMillis(threadPoolJobManager.getTimeout()); + if (millis > Integer.MAX_VALUE) { + LOGGER.warn( + "The value of {} is too large. The timeout will be set to the maximum value of {}", + name, + Integer.MAX_VALUE); + return Integer.MAX_VALUE; + } else { + return Integer.parseInt(Long.toString(millis)); + } } return Integer.parseInt(value); } private static CloseableHttpClient createHttpClient( - final int maxConnTotal, final int maxConnPerRoute) { + final int maxConnTotal, + final int maxConnPerRoute, + final ThreadPoolJobManager threadPoolJobManager) { final RequestConfig requestConfig = RequestConfig.custom() - .setConnectionRequestTimeout(getIntProperty("http.connectionRequestTimeout")) - .setConnectTimeout(getIntProperty("http.connectTimeout")) - .setSocketTimeout(getIntProperty("http.socketTimeout")) + .setConnectionRequestTimeout( + getTimeoutValue("http.connectionRequestTimeout", threadPoolJobManager)) + .setConnectTimeout(getTimeoutValue("http.connectTimeout", threadPoolJobManager)) + .setSocketTimeout(getTimeoutValue("http.socketTimeout", threadPoolJobManager)) .build(); final HttpClientBuilder httpClientBuilder = @@ -89,11 +114,19 @@ private static CloseableHttpClient createHttpClient( .setMaxConnTotal(maxConnTotal) .setMaxConnPerRoute(maxConnPerRoute) .setUserAgent(UserAgentCreator.getUserAgent()); - return httpClientBuilder.build(); + CloseableHttpClient closeableHttpClient = httpClientBuilder.build(); + LOGGER.debug( + "Created CloseableHttpClient using connectionRequestTimeout: {} connectTimeout: {}" + + " socketTimeout: {}", + getTimeoutValue("http.connectionRequestTimeout", threadPoolJobManager), + getTimeoutValue("http.connectTimeout", threadPoolJobManager), + getTimeoutValue("http.socketTimeout", threadPoolJobManager)); + return closeableHttpClient; } // allow extension only for testing @Override + @Nonnull public ConfigurableRequest createRequest( @Nonnull final URI uri, @Nonnull final HttpMethod httpMethod) { HttpRequestBase httpRequest = (HttpRequestBase) createHttpUriRequest(httpMethod, uri); @@ -161,20 +194,24 @@ public HttpMethod getMethod() { return HttpMethod.valueOf(this.request.getMethod()); } + @Nonnull @Override public String getMethodValue() { return this.request.getMethod(); } + @Nonnull public URI getURI() { return this.request.getURI(); } + @Nonnull @Override protected OutputStream getBodyInternal(@Nonnull final HttpHeaders headers) { return this.outputStream; } + @Nonnull @Override protected Response executeInternal(@Nonnull final HttpHeaders headers) throws IOException { CURRENT_CONFIGURATION.set(this.configuration); @@ -207,7 +244,7 @@ protected Response executeInternal(@Nonnull final HttpHeaders headers) throws IO } } - static class Response extends AbstractClientHttpResponse { + public static class Response extends AbstractClientHttpResponse { private static final Logger LOGGER = LoggerFactory.getLogger(Response.class); private static final AtomicInteger ID_COUNTER = new AtomicInteger(); private final HttpResponse response; @@ -224,6 +261,7 @@ public int getRawStatusCode() { return this.response.getStatusLine().getStatusCode(); } + @Nonnull @Override public String getStatusText() { return this.response.getStatusLine().getReasonPhrase(); @@ -247,6 +285,7 @@ public void close() { LOGGER.trace("Closed Http Response object: {}", this.id); } + @Nonnull @Override public synchronized InputStream getBody() throws IOException { if (this.inputStream == null) { @@ -262,6 +301,7 @@ public synchronized InputStream getBody() throws IOException { return this.inputStream; } + @Nonnull @Override public HttpHeaders getHeaders() { final HttpHeaders translatedHeaders = new HttpHeaders(); diff --git a/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java b/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java index a6fa026e3b..e91d531478 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java @@ -136,6 +136,10 @@ public final void setTimeout(final long timeout) { this.timeout = timeout; } + public final long getTimeout() { + return this.timeout; + } + public final void setAbandonedTimeout(final long abandonedTimeout) { this.abandonedTimeout = abandonedTimeout; } @@ -452,10 +456,13 @@ private boolean updateRegistry() { final SubmittedPrintJob printJob = submittedJobs.next(); if (!printJob.getReportFuture().isDone() && (isTimeoutExceeded(printJob) || isAbandoned(printJob))) { - LOGGER.info("Canceling job after timeout {}", printJob.getEntry().getReferenceId()); + LOGGER.info( + "About to attempt timeout based automatic cancellation of job {}", + printJob.getEntry().getReferenceId()); if (!printJob.getReportFuture().cancel(true)) { LOGGER.info( - "Could not cancel job after timeout {}", printJob.getEntry().getReferenceId()); + "Automatic cancellation after timeout failed for job {}", + printJob.getEntry().getReferenceId()); } // remove all canceled tasks from the work queue (otherwise the queue comparator // might stumble on non-PrintJob entries) diff --git a/core/src/main/resources/mapfish-spring-application-context.xml b/core/src/main/resources/mapfish-spring-application-context.xml index aaf2d532dd..2a42ddc332 100644 --- a/core/src/main/resources/mapfish-spring-application-context.xml +++ b/core/src/main/resources/mapfish-spring-application-context.xml @@ -62,7 +62,8 @@ - + + diff --git a/core/src/test/java/org/mapfish/print/TestHttpClientFactory.java b/core/src/test/java/org/mapfish/print/TestHttpClientFactory.java index 7d81666b3f..db8cf6e245 100644 --- a/core/src/test/java/org/mapfish/print/TestHttpClientFactory.java +++ b/core/src/test/java/org/mapfish/print/TestHttpClientFactory.java @@ -1,18 +1,18 @@ package org.mapfish.print; -import static org.junit.Assert.fail; - import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; +import javax.annotation.Nonnull; import org.apache.http.client.methods.HttpRequestBase; import org.mapfish.print.config.Configuration; import org.mapfish.print.http.ConfigurableRequest; import org.mapfish.print.http.MfClientHttpRequestFactory; import org.mapfish.print.http.MfClientHttpRequestFactoryImpl; +import org.mapfish.print.servlet.job.impl.ThreadPoolJobManager; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -27,7 +27,7 @@ public class TestHttpClientFactory extends MfClientHttpRequestFactoryImpl private final Map, Handler> handlers = new ConcurrentHashMap<>(); public TestHttpClientFactory() { - super(20, 10); + super(20, 10, new ThreadPoolJobManager()); } public void registerHandler(Predicate matcher, Handler handler) { @@ -37,8 +37,9 @@ public void registerHandler(Predicate matcher, Handler handler) { handlers.put(matcher, handler); } + @Nonnull @Override - public ConfigurableRequest createRequest(URI uri, final HttpMethod httpMethod) { + public ConfigurableRequest createRequest(@Nonnull URI uri, @Nonnull final HttpMethod httpMethod) { for (Map.Entry, Handler> entry : handlers.entrySet()) { if (entry.getKey().test(uri)) { try { @@ -75,18 +76,6 @@ public MockClientHttpRequest error404(URI uri, HttpMethod httpMethod) { request.setResponse(response); return request; } - - public MockClientHttpRequest failOnExecute(final URI uri, final HttpMethod httpMethod) { - MockClientHttpRequest request = - new MockClientHttpRequest(httpMethod, uri) { - @Override - protected ClientHttpResponse executeInternal() throws IOException { - fail("request should not be executed " + uri.toString()); - throw new IOException(); - } - }; - return request; - } } private static class TestConfigurableRequest implements ConfigurableRequest { @@ -106,11 +95,13 @@ public void setConfiguration(Configuration configuration) { // ignore } + @Nonnull @Override public ClientHttpResponse execute() throws IOException { return httpRequest.execute(); } + @Nonnull @Override public OutputStream getBody() throws IOException { return httpRequest.getBody(); @@ -121,18 +112,20 @@ public HttpMethod getMethod() { return httpRequest.getMethod(); } + @Nonnull @Override public String getMethodValue() { final HttpMethod method = httpRequest.getMethod(); - assert method != null; return method.name(); } + @Nonnull @Override public URI getURI() { return httpRequest.getURI(); } + @Nonnull @Override public HttpHeaders getHeaders() { return httpRequest.getHeaders(); diff --git a/core/src/test/java/org/mapfish/print/http/ConfigFileResolvingRequestTest.java b/core/src/test/java/org/mapfish/print/http/ConfigFileResolvingRequestTest.java index d52cab391e..331d3964bc 100644 --- a/core/src/test/java/org/mapfish/print/http/ConfigFileResolvingRequestTest.java +++ b/core/src/test/java/org/mapfish/print/http/ConfigFileResolvingRequestTest.java @@ -29,6 +29,7 @@ public void executeInternalShouldDoDataUriRequestWhenSchemeIsData() throws IOExc // Then assertEquals("OK", resp.getStatusText()); + resp.close(); } @Test @@ -46,6 +47,7 @@ public void httpRequestWithRetryShouldSucceedAtSecondAttempt() throws IOExceptio // Then assertEquals(200, resp.getRawStatusCode()); + resp.close(); } @Test @@ -66,6 +68,7 @@ public void httpRequestWithRetryShouldSucceedDespiteException() throws IOExcepti // Then assertEquals(200, resp.getRawStatusCode()); + resp.close(); } @Test @@ -81,9 +84,10 @@ public void httpRequestWithRetryDoNotBlockWhenFailing() throws IOException { try { ClientHttpResponse resp = req.executeInternal(new HttpHeaders()); fail("Should not have return the response " + resp); + resp.close(); } catch (PrintException e) { // Then - assertEquals("Fetching failed URI resource http://ex.com, error code 500", e.getMessage()); + assertEquals("Failed fetching http://ex.com", e.getMessage()); } } diff --git a/core/src/test/java/org/mapfish/print/http/MfClientHttpRequestFactoryImpl_ResponseTest.java b/core/src/test/java/org/mapfish/print/http/MfClientHttpRequestFactoryImplTest.java similarity index 57% rename from core/src/test/java/org/mapfish/print/http/MfClientHttpRequestFactoryImpl_ResponseTest.java rename to core/src/test/java/org/mapfish/print/http/MfClientHttpRequestFactoryImplTest.java index eeb312eede..bfadcb69d7 100644 --- a/core/src/test/java/org/mapfish/print/http/MfClientHttpRequestFactoryImpl_ResponseTest.java +++ b/core/src/test/java/org/mapfish/print/http/MfClientHttpRequestFactoryImplTest.java @@ -3,19 +3,17 @@ import static org.junit.Assert.assertEquals; import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; -import java.io.IOException; import java.net.InetSocketAddress; import java.net.URI; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.mapfish.print.servlet.job.impl.ThreadPoolJobManager; import org.springframework.http.HttpMethod; import org.springframework.http.client.ClientHttpResponse; -public class MfClientHttpRequestFactoryImpl_ResponseTest { +public class MfClientHttpRequestFactoryImplTest { private static final int TARGET_PORT = 33212; private static HttpServer targetServer; @@ -35,23 +33,23 @@ public static void tearDown() { public void testGetHeaders() throws Exception { targetServer.createContext( "/request", - new HttpHandler() { - @Override - public void handle(HttpExchange httpExchange) throws IOException { - final Headers responseHeaders = httpExchange.getResponseHeaders(); - responseHeaders.add("Content-Type", "application/json; charset=utf8"); - httpExchange.sendResponseHeaders(200, 0); - httpExchange.close(); - } + httpExchange -> { + final Headers responseHeaders = httpExchange.getResponseHeaders(); + responseHeaders.add("Content-Type", "application/json; charset=utf8"); + httpExchange.sendResponseHeaders(200, 0); + httpExchange.close(); }); - MfClientHttpRequestFactoryImpl factory = new MfClientHttpRequestFactoryImpl(20, 10); + MfClientHttpRequestFactoryImpl factory = + new MfClientHttpRequestFactoryImpl(20, 10, new ThreadPoolJobManager()); final ConfigurableRequest request = factory.createRequest( new URI("http://" + HttpProxyTest.LOCALHOST + ":" + TARGET_PORT + "/request"), HttpMethod.GET); - final ClientHttpResponse response = request.execute(); - assertEquals("application/json; charset=utf8", response.getHeaders().getFirst("Content-Type")); + try (ClientHttpResponse response = request.execute()) { + assertEquals( + "application/json; charset=utf8", response.getHeaders().getFirst("Content-Type")); + } } } diff --git a/examples/src/test/java/org/mapfish/print/AbstractApiTest.java b/examples/src/test/java/org/mapfish/print/AbstractApiTest.java index 7601a2b5ef..558ee4b5d0 100644 --- a/examples/src/test/java/org/mapfish/print/AbstractApiTest.java +++ b/examples/src/test/java/org/mapfish/print/AbstractApiTest.java @@ -10,6 +10,7 @@ import java.util.Map; import org.apache.commons.io.IOUtils; import org.mapfish.print.http.MfClientHttpRequestFactoryImpl; +import org.mapfish.print.servlet.job.impl.ThreadPoolJobManager; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpRequest; @@ -21,7 +22,7 @@ public abstract class AbstractApiTest { protected static final String PRINT_SERVER = "http://print:8080/"; protected ClientHttpRequestFactory httpRequestFactory = - new MfClientHttpRequestFactoryImpl(10, 10); + new MfClientHttpRequestFactoryImpl(10, 10, new ThreadPoolJobManager()); protected ClientHttpRequest getRequest(String path, HttpMethod method) throws IOException, URISyntaxException {