Per client HTTP connection pooling Implementation with static factory method
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/934bb74f Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/934bb74f Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/934bb74f Branch: refs/heads/master Commit: 934bb74f77a53eaaea0ea6e3425bd6b40c02d454 Parents: 971c217 Author: Guglielmo Nigri <[email protected]> Authored: Thu Nov 5 12:45:30 2015 +0100 Committer: Guglielmo Nigri <[email protected]> Committed: Thu Nov 5 12:45:30 2015 +0100 ---------------------------------------------------------------------- .../brooklyn/rest/client/BrooklynApi.java | 172 ++++++++++++++----- .../rest/client/BrooklynApiFactory.java | 29 ---- .../rest/client/DefaultBrooklynApiFactory.java | 50 ------ .../rest/client/PoolingBrooklynApiFactory.java | 108 ------------ .../ApplicationResourceIntegrationTest.java | 4 +- .../rest/client/BrooklynApiRestClientTest.java | 4 +- 6 files changed, 131 insertions(+), 236 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/934bb74f/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java ---------------------------------------------------------------------- diff --git a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java index 184b659..e848f99 100644 --- a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java +++ b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java @@ -30,12 +30,18 @@ import java.net.URL; import javax.annotation.Nullable; import javax.ws.rs.core.Response; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import org.apache.http.auth.AuthScope; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.impl.client.*; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.jboss.resteasy.client.ClientExecutor; -import org.jboss.resteasy.client.ClientRequest; import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.client.ProxyFactory; import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor; @@ -68,18 +74,18 @@ import com.wordnik.swagger.core.ApiOperation; /** * @author Adam Lowe - */ + */ @SuppressWarnings("deprecation") public class BrooklynApi { private final String target; private final ClientExecutor clientExecutor; + private final int maxPoolSize; + private final int timeOutInMillis; private static final Logger LOG = LoggerFactory.getLogger(BrooklynApi.class); /** - * @deprecated since 0.9.0. Use {@link BrooklynApiFactory#getBrooklynApi(java.net.URL, String, String)} instead - * @see org.apache.brooklyn.rest.client.DefaultBrooklynApiFactory - * @see org.apache.brooklyn.rest.client.PoolingBrooklynApiFactory + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String)} instead */ @Deprecated public BrooklynApi(URL endpoint) { @@ -87,9 +93,7 @@ public class BrooklynApi { } /** - * @deprecated since 0.9.0. Use {@link BrooklynApiFactory#getBrooklynApi(java.net.URL, String, String)} instead - * @see org.apache.brooklyn.rest.client.DefaultBrooklynApiFactory - * @see org.apache.brooklyn.rest.client.PoolingBrooklynApiFactory + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String)} instead */ @Deprecated public BrooklynApi(String endpoint) { @@ -98,9 +102,7 @@ public class BrooklynApi { } /** - * @deprecated since 0.9.0. Use {@link BrooklynApiFactory#getBrooklynApi(java.net.URL, String, String)} instead - * @see org.apache.brooklyn.rest.client.DefaultBrooklynApiFactory - * @see org.apache.brooklyn.rest.client.PoolingBrooklynApiFactory + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead */ @Deprecated public BrooklynApi(URL endpoint, String username, String password) { @@ -108,9 +110,7 @@ public class BrooklynApi { } /** - * @deprecated since 0.9.0. Use {@link BrooklynApiFactory#getBrooklynApi(java.net.URL, String, String)} instead - * @see org.apache.brooklyn.rest.client.DefaultBrooklynApiFactory - * @see org.apache.brooklyn.rest.client.PoolingBrooklynApiFactory + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead */ @Deprecated public BrooklynApi(String endpoint, String username, String password) { @@ -118,9 +118,7 @@ public class BrooklynApi { } /** - * @deprecated since 0.9.0. Use {@link BrooklynApiFactory#getBrooklynApi(java.net.URL, String, String)} instead - * @see org.apache.brooklyn.rest.client.DefaultBrooklynApiFactory - * @see org.apache.brooklyn.rest.client.PoolingBrooklynApiFactory + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead */ @Deprecated public BrooklynApi(URL endpoint, @Nullable Credentials credentials) { @@ -128,43 +126,131 @@ public class BrooklynApi { } /** - * @deprecated since 0.9.0. Use {@link BrooklynApiFactory#getBrooklynApi(java.net.URL, String, String)} instead - * @see org.apache.brooklyn.rest.client.DefaultBrooklynApiFactory - * @see org.apache.brooklyn.rest.client.PoolingBrooklynApiFactory + * Creates a BrooklynApi using an HTTP connection pool + * + * @deprecated since 0.9.0. Use {@link BrooklynApi#newInstance(String, String, String)} instead */ @Deprecated public BrooklynApi(String endpoint, @Nullable Credentials credentials) { + this(endpoint, credentials, 20, 5000); + } + + /** + * Creates a BrooklynApi using a custom ClientExecutor + * + * @param endpoint the Brooklyn endpoint + * @param clientExecutor the ClientExecutor + * @see #getClientExecutor(org.apache.http.auth.Credentials) + */ + public BrooklynApi(URL endpoint, ClientExecutor clientExecutor) { + this.target = checkNotNull(endpoint, "endpoint").toString(); + this.maxPoolSize = -1; + this.timeOutInMillis = -1; + this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor"); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param credentials user credentials or null + * @param maxPoolSize maximum pool size + * @param timeOutInMillis connection timeout in milliseconds + */ + public BrooklynApi(String endpoint, @Nullable Credentials credentials, int maxPoolSize, int timeOutInMillis) { try { new URL(checkNotNull(endpoint, "endpoint")); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } - this.target = endpoint; - if (credentials != null) { - DefaultHttpClient httpClient = new DefaultHttpClient(); - httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, credentials); - this.clientExecutor = new ApacheHttpClient4Executor(httpClient); - } else { - this.clientExecutor = ClientRequest.getDefaultExecutor(); + this.maxPoolSize = maxPoolSize; + this.timeOutInMillis = timeOutInMillis; + this.clientExecutor = getClientExecutor(credentials); + } + + private Supplier<PoolingHttpClientConnectionManager> connectionManagerSupplier = Suppliers.memoize(new Supplier<PoolingHttpClientConnectionManager>() { + @Override + public PoolingHttpClientConnectionManager get() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(maxPoolSize); + connManager.setDefaultMaxPerRoute(maxPoolSize); + return connManager; } + }); + + private Supplier<RequestConfig> reqConfSupplier = Suppliers.memoize(new Supplier<RequestConfig>() { + @Override + public RequestConfig get() { + return RequestConfig.custom() + .setConnectTimeout(timeOutInMillis) + .setConnectionRequestTimeout(timeOutInMillis) + .build(); + } + }); + + /** + * Creates a ClientExecutor for this BrooklynApi + */ + protected ClientExecutor getClientExecutor(Credentials credentials) { + CredentialsProvider provider = new BasicCredentialsProvider(); + if (credentials != null) provider.setCredentials(AuthScope.ANY, credentials); + + CloseableHttpClient httpClient = HttpClients.custom() + .setDefaultCredentialsProvider(provider) + .setDefaultRequestConfig(reqConfSupplier.get()) + .setConnectionManager(connectionManagerSupplier.get()) + .build(); + + return new ApacheHttpClient4Executor(httpClient); } /** - * @deprecated since 0.9.0. Use {@link BrooklynApiFactory#getBrooklynApi(java.net.URL, String, String)} instead - * @see org.apache.brooklyn.rest.client.DefaultBrooklynApiFactory - * @see org.apache.brooklyn.rest.client.PoolingBrooklynApiFactory + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @return a new BrooklynApi instance */ - @Deprecated - public BrooklynApi(URL endpoint, ClientExecutor clientExecutor) { - this.target = checkNotNull(endpoint, "endpoint").toString(); - this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor"); + public static BrooklynApi newInstance(String endpoint) { + return new BrooklynApi(endpoint, null); } - // to be used by factories - BrooklynApi(ClientExecutor clientExecutor, URL endpoint) { - this.target = checkNotNull(endpoint, "endpoint").toString(); - this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor"); + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param maxPoolSize maximum connection pool size + * @param timeOutInMillis connection timeout in millisecond + * @return a new BrooklynApi instance + */ + public static BrooklynApi newInstance(String endpoint, int maxPoolSize, int timeOutInMillis) { + return new BrooklynApi(endpoint, null, maxPoolSize, timeOutInMillis); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param username for authentication + * @param password for authentication + * @return a new BrooklynApi instance + */ + public static BrooklynApi newInstance(String endpoint, String username, String password) { + return new BrooklynApi(endpoint, new UsernamePasswordCredentials(username, password)); + } + + /** + * Creates a BrooklynApi using an HTTP connection pool + * + * @param endpoint the Brooklyn endpoint + * @param username for authentication + * @param password for authentication + * @param maxPoolSize maximum connection pool size + * @param timeOutInMillis connection timeout in millisecond + * @return a new BrooklynApi instance + */ + public static BrooklynApi newInstance(String endpoint, String username, String password, int maxPoolSize, int timeOutInMillis) { + return new BrooklynApi(endpoint, new UsernamePasswordCredentials(username, password), maxPoolSize, timeOutInMillis); } @SuppressWarnings("unchecked") @@ -172,7 +258,7 @@ public class BrooklynApi { final T result0 = ProxyFactory.create(clazz, target, clientExecutor); return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, new InvocationHandler() { @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Object result1 = method.invoke(result0, args); Class<?> type = String.class; @@ -191,11 +277,11 @@ public class BrooklynApi { e = ((InvocationTargetException)e).getTargetException(); } throw Exceptions.propagate(e); - } + } } - + private boolean isStatusCodeHealthy(int code) { return (code>=200 && code<=299); } - + private Class<?> getClassFromMethodAnnotationOrDefault(Method method, Class<?> def){ Class<?> type; try{ http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/934bb74f/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiFactory.java ---------------------------------------------------------------------- diff --git a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiFactory.java b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiFactory.java deleted file mode 100644 index b32c227..0000000 --- a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.rest.client; - -import java.net.URL; - -/** - * Creates {@link BrooklynApi} instances. - */ -public interface BrooklynApiFactory { - - BrooklynApi getBrooklynApi(URL endpoint, String username, String password); -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/934bb74f/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/DefaultBrooklynApiFactory.java ---------------------------------------------------------------------- diff --git a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/DefaultBrooklynApiFactory.java b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/DefaultBrooklynApiFactory.java deleted file mode 100644 index 48e0eeb..0000000 --- a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/DefaultBrooklynApiFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.rest.client; - -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.impl.client.DefaultHttpClient; -import org.jboss.resteasy.client.ClientExecutor; -import org.jboss.resteasy.client.ClientRequest; -import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor; - -import java.net.URL; - -/** - * BrooklynApi factory. - * <p/> - * This Factory creates BrooklynApi instances that use an {@link ApacheHttpClient4Executor} - */ -public class DefaultBrooklynApiFactory implements BrooklynApiFactory { - - @SuppressWarnings("deprecation") - @Override - public BrooklynApi getBrooklynApi(URL endpoint, String username, String password) { - ClientExecutor clientExecutor; - if (username != null) { - DefaultHttpClient httpClient = new DefaultHttpClient(); - httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); - clientExecutor = new ApacheHttpClient4Executor(httpClient); - } else { - clientExecutor = ClientRequest.getDefaultExecutor(); - } - return new BrooklynApi(clientExecutor, endpoint); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/934bb74f/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/PoolingBrooklynApiFactory.java ---------------------------------------------------------------------- diff --git a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/PoolingBrooklynApiFactory.java b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/PoolingBrooklynApiFactory.java deleted file mode 100644 index f58f4f5..0000000 --- a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/PoolingBrooklynApiFactory.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.rest.client; - -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.jboss.resteasy.client.ClientExecutor; -import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor; - -import java.net.URL; - -/** - * BrooklynApi factory. - * <p/> - * This Factory uses a {@link PoolingHttpClientConnectionManager} to reuse HTTP connections. - */ -public class PoolingBrooklynApiFactory implements BrooklynApiFactory { - - private Supplier<PoolingHttpClientConnectionManager> connectionManagerSupplier = Suppliers.memoize(new Supplier<PoolingHttpClientConnectionManager>() { - @Override - public PoolingHttpClientConnectionManager get() { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - connManager.setMaxTotal(maxPoolSize); - connManager.setDefaultMaxPerRoute(maxPoolSize); - return connManager; - } - }); - - private Supplier<RequestConfig> reqConfSupplier = Suppliers.memoize(new Supplier<RequestConfig>() { - @Override - public RequestConfig get() { - - return RequestConfig.custom() - .setConnectTimeout(timeOutInMillis) - .setConnectionRequestTimeout(timeOutInMillis) - .build(); - } - }); - - protected final int maxPoolSize; - protected final int timeOutInMillis; - - @SuppressWarnings("deprecation") - private ClientExecutor getPoolingClientExecutor(Credentials credentials) { - CredentialsProvider provider = new BasicCredentialsProvider(); - provider.setCredentials(AuthScope.ANY, credentials); - - CloseableHttpClient httpClient = HttpClients.custom() - .setDefaultCredentialsProvider(provider) - .setDefaultRequestConfig(reqConfSupplier.get()) - .setConnectionManager(connectionManagerSupplier.get()) - .build(); - - return new ApacheHttpClient4Executor(httpClient); - } - - /** - * Creates a new PoolingBrooklynApiFactory with a max pool size of 20 - * connections, and a connection timeout of 5000 milliseconds - */ - public PoolingBrooklynApiFactory() { - this(20, 5000); - } - - /** - * Creates a new PoolingBrooklynApiFactory - * @param maxPoolSize the maximum size of the pool - * @param timeOutInMillis connection timeout in milliseconds - */ - public PoolingBrooklynApiFactory(int maxPoolSize, int timeOutInMillis) { - this.maxPoolSize = maxPoolSize; - this.timeOutInMillis = timeOutInMillis; - } - - @SuppressWarnings("deprecation") - @Override - public BrooklynApi getBrooklynApi(URL endpoint, String username, String password) { - UsernamePasswordCredentials credentials = - (username != null) ? new UsernamePasswordCredentials(username, password) - : null; - return new BrooklynApi(getPoolingClientExecutor(credentials), endpoint); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/934bb74f/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java ---------------------------------------------------------------------- diff --git a/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java index 7015113..645fd8b 100644 --- a/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java +++ b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java @@ -89,9 +89,7 @@ public class ApplicationResourceIntegrationTest { .managementContext(getManagementContext()) .start(); - DefaultBrooklynApiFactory defaultBrooklynApiFactory = new DefaultBrooklynApiFactory(); - - api = defaultBrooklynApiFactory.getBrooklynApi(new URL("http://localhost:" + server.getConnectors()[0].getPort() + "/"), null, null); + api = BrooklynApi.newInstance("http://localhost:" + server.getConnectors()[0].getPort() + "/"); } @AfterClass(alwaysRun = true) http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/934bb74f/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java ---------------------------------------------------------------------- diff --git a/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java index abc3bfe..f952c01 100644 --- a/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java +++ b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java @@ -71,9 +71,7 @@ public class BrooklynApiRestClientTest { .securityProvider(TestSecurityProvider.class) .start(); - DefaultBrooklynApiFactory defaultBrooklynApiFactory = new DefaultBrooklynApiFactory(); - - api = defaultBrooklynApiFactory.getBrooklynApi(new URL("http://localhost:" + server.getConnectors()[0].getPort() + "/"), + api = BrooklynApi.newInstance("http://localhost:" + server.getConnectors()[0].getPort() + "/", TestSecurityProvider.USER, TestSecurityProvider.PASSWORD); }
