1515import com .joyent .manta .config .DefaultsConfigContext ;
1616import com .joyent .manta .exception .ConfigurationException ;
1717import com .joyent .manta .util .MantaVersion ;
18+ import org .apache .commons .lang3 .BooleanUtils ;
1819import org .apache .commons .lang3 .ObjectUtils ;
1920import org .apache .commons .lang3 .Validate ;
2021import org .apache .http .Header ;
@@ -118,36 +119,40 @@ public class MantaConnectionFactory implements Closeable, MantaMBeanable {
118119 /**
119120 * Create new instance using the passed configuration.
120121 *
121- * @param config configuration of the connection parameters
122- * @param keyPair cryptographic signing key pair used for HTTP signatures
123- * @param signer Signer configured to use the given keyPair
122+ * @param config configuration of the connection parameters
123+ * @param keyPair cryptographic signing key pair used for HTTP signatures
124+ * @param signer Signer configured to use the given keyPair
124125 */
125126 public MantaConnectionFactory (final ConfigContext config ,
126127 final KeyPair keyPair ,
127128 final ThreadLocalSigner signer ) {
128- Validate .notNull (config , "Configuration context must not be null" );
129+ this (config , keyPair , signer , null );
130+ }
129131
132+ /**
133+ * Create a new instance based on a shared {@link HttpClientBuilder} and {@link HttpClientConnectionManager}.
134+ *
135+ * @param config configuration of the connection parameters
136+ * @param keyPair cryptographic signing key pair used for HTTP signatures
137+ * @param signer Signer configured to use the given keyPair
138+ * @param connectionFactoryConfigurator existing HttpClient objects to reuse
139+ */
140+ public MantaConnectionFactory (final ConfigContext config ,
141+ final KeyPair keyPair ,
142+ final ThreadLocalSigner signer ,
143+ final MantaConnectionFactoryConfigurator connectionFactoryConfigurator ) {
144+ Validate .notNull (config , "Configuration context must not be null" );
130145 this .config = config ;
131146
132- this .connectionManager = buildConnectionManager ();
133-
134- this .httpClientBuilder = createBuilder ();
135-
136- final boolean authDisabled = ObjectUtils .firstNonNull (
137- config .noAuth (),
138- DefaultsConfigContext .DEFAULT_NO_AUTH );
139-
140- if (!authDisabled ) {
141- Validate .notNull (keyPair , "KeyPair must not be null if authentication is enabled" );
142- Validate .notNull (signer , "Signer must not be null if authentication is enabled" );
143-
144- // pass true directly to the constructor because auth is enabled
145- final HttpRequestInterceptor authInterceptor = new HttpSignatureRequestInterceptor (
146- new HttpSignatureAuthScheme (keyPair , signer ),
147- new UsernamePasswordCredentials (config .getMantaUser (), null ),
148- true );
149- this .httpClientBuilder .addInterceptorLast (authInterceptor );
147+ if (connectionFactoryConfigurator != null ) {
148+ this .connectionManager = null ;
149+ this .httpClientBuilder = connectionFactoryConfigurator .getHttpClientBuilder ();
150+ } else {
151+ this .connectionManager = buildConnectionManager ();
152+ this .httpClientBuilder = createStandardBuilder ();
150153 }
154+
155+ configureHttpClientBuilderDefaults (keyPair , signer );
151156 }
152157
153158 /**
@@ -186,6 +191,7 @@ protected SocketConfig buildSocketConfig() {
186191
187192 /**
188193 * Builds and configures a {@link ConnectionConfig} instance.
194+ *
189195 * @return fully configured instance
190196 */
191197 protected ConnectionConfig buildConnectionConfig () {
@@ -204,7 +210,7 @@ protected ConnectionConfig buildConnectionConfig() {
204210 *
205211 * @return fully configured connection manager
206212 */
207- protected PoolingHttpClientConnectionManager buildConnectionManager () {
213+ protected HttpClientConnectionManager buildConnectionManager () {
208214 final int maxConns = ObjectUtils .firstNonNull (
209215 config .getMaximumConnections (),
210216 DefaultsConfigContext .DEFAULT_MAX_CONNS );
@@ -241,7 +247,7 @@ protected PoolingHttpClientConnectionManager buildConnectionManager() {
241247 *
242248 * @return configured instance
243249 */
244- protected HttpClientBuilder createBuilder () {
250+ protected HttpClientBuilder createStandardBuilder () {
245251 final int maxConns = ObjectUtils .firstNonNull (
246252 config .getMaximumConnections (),
247253 DefaultsConfigContext .DEFAULT_MAX_CONNS );
@@ -264,7 +270,6 @@ protected HttpClientBuilder createBuilder() {
264270 final HttpClientBuilder builder = HttpClients .custom ()
265271 .disableAuthCaching ()
266272 .disableCookieManagement ()
267- .setDefaultHeaders (HEADERS )
268273 .setUserAgent (USER_AGENT )
269274 .setConnectionReuseStrategy (new DefaultConnectionReuseStrategy ())
270275 .setMaxConnTotal (maxConns )
@@ -274,24 +279,51 @@ protected HttpClientBuilder createBuilder() {
274279 .setRequestExecutor (new MantaHttpRequestExecutor ())
275280 .setConnectionBackoffStrategy (new DefaultBackoffStrategy ());
276281
282+ final HttpHost proxyHost = findProxyServer ();
283+
284+ if (proxyHost != null ) {
285+ builder .setProxy (proxyHost );
286+ }
287+
288+ return builder ;
289+ }
290+
291+ /**
292+ * Apply required configuration to an HttpClientBuilder that may have been created by us or provided externally.
293+ *
294+ * @param keyPair the keypair to use with signature authentication
295+ * @param signer Signer configured to use the given keyPair
296+ */
297+ private void configureHttpClientBuilderDefaults (final KeyPair keyPair ,
298+ final ThreadLocalSigner signer ) {
277299 if (config .getRetries () > 0 ) {
278- builder .setRetryHandler (new MantaHttpRequestRetryHandler (config ))
279- .setServiceUnavailableRetryStrategy (new MantaServiceUnavailableRetryStrategy (config ));
300+ httpClientBuilder .setRetryHandler (new MantaHttpRequestRetryHandler (config ));
301+ httpClientBuilder .setServiceUnavailableRetryStrategy (new MantaServiceUnavailableRetryStrategy (config ));
280302 } else {
281303 LOGGER .info ("Retry of failed requests is disabled" );
282- builder .disableAutomaticRetries ();
304+ httpClientBuilder .disableAutomaticRetries ();
283305 }
284306
285- final HttpHost proxyHost = findProxyServer ();
286-
287- if (proxyHost != null ) {
288- builder . setProxy ( proxyHost );
307+ // attach the connection manager if it was created by us
308+ // users providing a custom HttpClientBuilder are expected to wire this up themselves
309+ if (this . connectionManager != null ) {
310+ httpClientBuilder . setConnectionManager ( this . connectionManager );
289311 }
290312
291- builder . addInterceptorFirst ( new RequestIdInterceptor () );
292- builder . setConnectionManager ( this . connectionManager );
313+ httpClientBuilder . setDefaultHeaders ( HEADERS );
314+ httpClientBuilder . addInterceptorFirst ( new RequestIdInterceptor () );
293315
294- return builder ;
316+ if (BooleanUtils .isNotTrue (config .noAuth ())) {
317+ Validate .notNull (keyPair , "KeyPair must not be null if authentication is enabled" );
318+ Validate .notNull (signer , "Signer must not be null if authentication is enabled" );
319+
320+ // pass true directly to the constructor because auth is enabled
321+ final HttpRequestInterceptor authInterceptor = new HttpSignatureRequestInterceptor (
322+ new HttpSignatureAuthScheme (keyPair , signer ),
323+ new UsernamePasswordCredentials (config .getMantaUser (), null ),
324+ true );
325+ this .httpClientBuilder .addInterceptorLast (authInterceptor );
326+ }
295327 }
296328
297329 /**
@@ -343,16 +375,6 @@ public CloseableHttpClient createConnection() {
343375 return httpClientBuilder .build ();
344376 }
345377
346- /**
347- * package-private method for building a {@link MantaHttpRequestFactory} from this object's
348- * config. Should be removed with the deprecated constructor for {@link MantaApacheHttpClientContext}.
349- *
350- * @return a request factory pointed at the same url as {@code this}
351- */
352- ConfigContext getConfig () {
353- return config ;
354- }
355-
356378 @ Override
357379 public DynamicMBean toMBean () {
358380 if (!(connectionManager instanceof PoolingHttpClientConnectionManager )) {
@@ -365,8 +387,10 @@ public DynamicMBean toMBean() {
365387 @ Override
366388 public void close () throws IOException {
367389 if (connectionManager == null ) {
390+ // user provided their own connectionManager in the httpClientBuilder
368391 return ;
369392 }
393+
370394 connectionManager .shutdown ();
371395 }
372396}
0 commit comments