Repository: incubator-brooklyn Updated Branches: refs/heads/master f52d9e052 -> 40de86652
HTTP connection pooling for BrooklynApi clients - introduce factories to create clients - PoolingBrooklynApiFactory uses PoolingHttpClientConnectionManager - DefaultBrooklynApiFactory replaces the old BrooklynApi constructors using a new ApacheHttpClient4Executor for each client - deprecate existing BrooklynApi constructors Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/971c217d Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/971c217d Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/971c217d Branch: refs/heads/master Commit: 971c217d220986aece361b312b0793e4239d3d26 Parents: 48e4fe3 Author: googlielmo <[email protected]> Authored: Wed Nov 4 14:30:05 2015 +0100 Committer: Guglielmo Nigri <[email protected]> Committed: Wed Nov 4 15:43:12 2015 +0100 ---------------------------------------------------------------------- .../brooklyn/rest/client/BrooklynApi.java | 52 ++++++++- .../rest/client/BrooklynApiFactory.java | 29 +++++ .../rest/client/DefaultBrooklynApiFactory.java | 50 +++++++++ .../rest/client/PoolingBrooklynApiFactory.java | 108 +++++++++++++++++++ .../ApplicationResourceIntegrationTest.java | 5 +- .../rest/client/BrooklynApiRestClientTest.java | 5 +- 6 files changed, 245 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/971c217d/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 fa3b7ee..184b659 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 @@ -33,7 +33,7 @@ import javax.ws.rs.core.Response; import org.apache.http.auth.AuthScope; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.client.*; import org.jboss.resteasy.client.ClientExecutor; import org.jboss.resteasy.client.ClientRequest; import org.jboss.resteasy.client.ClientResponse; @@ -76,27 +76,63 @@ public class BrooklynApi { private final ClientExecutor clientExecutor; 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 public BrooklynApi(URL endpoint) { this(checkNotNull(endpoint, "endpoint").toString()); } + /** + * @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 public BrooklynApi(String endpoint) { // username/password cannot be null, but credentials can this(endpoint, null); } + /** + * @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 public BrooklynApi(URL endpoint, String username, String password) { this(endpoint.toString(), new UsernamePasswordCredentials(username, password)); } + /** + * @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 public BrooklynApi(String endpoint, String username, String password) { this(endpoint, new UsernamePasswordCredentials(username, password)); } + /** + * @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 public BrooklynApi(URL endpoint, @Nullable Credentials credentials) { this(endpoint.toString(), credentials); } + /** + * @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 public BrooklynApi(String endpoint, @Nullable Credentials credentials) { try { new URL(checkNotNull(endpoint, "endpoint")); @@ -114,11 +150,23 @@ 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 public BrooklynApi(URL endpoint, ClientExecutor clientExecutor) { this.target = checkNotNull(endpoint, "endpoint").toString(); this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor"); } + // to be used by factories + BrooklynApi(ClientExecutor clientExecutor, URL endpoint) { + this.target = checkNotNull(endpoint, "endpoint").toString(); + this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor"); + } + @SuppressWarnings("unchecked") private <T> T proxy(Class<T> clazz) { final T result0 = ProxyFactory.create(clazz, target, clientExecutor); @@ -252,7 +300,7 @@ public class BrooklynApi { } /** - * @deprecated Use {@link #getEntity(Response, GenericType)} instead. + * @deprecated since 0.9.0. Use {@link #getEntity(Response, GenericType)} instead. */ @Deprecated public static <T> T getEntityGeneric(Response response, GenericType<T> type) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/971c217d/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 new file mode 100644 index 0000000..b32c227 --- /dev/null +++ b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApiFactory.java @@ -0,0 +1,29 @@ +/* + * 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/971c217d/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 new file mode 100644 index 0000000..48e0eeb --- /dev/null +++ b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/DefaultBrooklynApiFactory.java @@ -0,0 +1,50 @@ +/* + * 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/971c217d/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 new file mode 100644 index 0000000..f58f4f5 --- /dev/null +++ b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/PoolingBrooklynApiFactory.java @@ -0,0 +1,108 @@ +/* + * 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/971c217d/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 61facc7..7015113 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 @@ -22,6 +22,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; +import java.net.URL; import java.util.Collection; import javax.ws.rs.core.Response; @@ -88,7 +89,9 @@ public class ApplicationResourceIntegrationTest { .managementContext(getManagementContext()) .start(); - api = new BrooklynApi("http://localhost:" + server.getConnectors()[0].getPort() + "/"); + DefaultBrooklynApiFactory defaultBrooklynApiFactory = new DefaultBrooklynApiFactory(); + + api = defaultBrooklynApiFactory.getBrooklynApi(new URL("http://localhost:" + server.getConnectors()[0].getPort() + "/"), null, null); } @AfterClass(alwaysRun = true) http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/971c217d/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 62c95b6..abc3bfe 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 @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.rest.client; +import java.net.URL; import java.util.List; import java.util.Map; @@ -70,7 +71,9 @@ public class BrooklynApiRestClientTest { .securityProvider(TestSecurityProvider.class) .start(); - api = new BrooklynApi("http://localhost:" + server.getConnectors()[0].getPort() + "/", + DefaultBrooklynApiFactory defaultBrooklynApiFactory = new DefaultBrooklynApiFactory(); + + api = defaultBrooklynApiFactory.getBrooklynApi(new URL("http://localhost:" + server.getConnectors()[0].getPort() + "/"), TestSecurityProvider.USER, TestSecurityProvider.PASSWORD); }
