This is an automated email from the ASF dual-hosted git repository. pivotalsarge pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push: new 81c5777 GEODE-4511: Switch to lazy initialization of the default pool. (#1420) 81c5777 is described below commit 81c5777c116d2e220e2ee550b3fc89bac4cbba72 Author: Michael "Sarge" Dodge <mdo...@pivotal.io> AuthorDate: Mon Feb 12 11:44:51 2018 -0800 GEODE-4511: Switch to lazy initialization of the default pool. (#1420) * GEODE-4511: Switch to lazy initialization of the default pool. * GEODE-4511: Address review comments. * GEODE-4511: Fix JUnit test that inexplicably passed locally. --- .../geode/cache/client/ClientCacheFactory.java | 7 +- .../client/internal/ClientRegionFactoryImpl.java | 6 +- .../cache/client/internal/InternalClientCache.java | 2 +- .../geode/internal/cache/GemFireCacheImpl.java | 146 +++++++++------------ .../geode/internal/cache/PoolFactoryImpl.java | 48 ++++++- .../cache/xmlcache/ClientCacheCreation.java | 2 - .../cache/client/ClientCacheFactoryJUnitTest.java | 1 + .../tier/sockets/ClientServerMiscDUnitTest.java | 4 + .../apache/geode/security/ClientAuthDUnitTest.java | 28 +++- .../geode/test/dunit/rules/ClusterStartupRule.java | 25 ++++ 10 files changed, 168 insertions(+), 101 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/cache/client/ClientCacheFactory.java b/geode-core/src/main/java/org/apache/geode/cache/client/ClientCacheFactory.java index 5666cf7..4da8e77 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/client/ClientCacheFactory.java +++ b/geode-core/src/main/java/org/apache/geode/cache/client/ClientCacheFactory.java @@ -250,12 +250,7 @@ public class ClientCacheFactory { } // check if pool is compatible - Pool pool = instance.determineDefaultPool(this.pf); - if (pool == null) { - if (instance.getDefaultPool() != null) { - throw new IllegalStateException("Existing cache's default pool was not compatible"); - } - } + instance.validatePoolFactory(this.pf); // Check if cache configuration matches. cacheConfig.validateCacheConfig(instance); diff --git a/geode-core/src/main/java/org/apache/geode/cache/client/internal/ClientRegionFactoryImpl.java b/geode-core/src/main/java/org/apache/geode/cache/client/internal/ClientRegionFactoryImpl.java index f5a35ff..b679e63 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/client/internal/ClientRegionFactoryImpl.java +++ b/geode-core/src/main/java/org/apache/geode/cache/client/internal/ClientRegionFactoryImpl.java @@ -16,6 +16,8 @@ package org.apache.geode.cache.client.internal; import static org.apache.commons.lang.StringUtils.isEmpty; +import java.util.Objects; + import org.apache.geode.cache.AttributesFactory; import org.apache.geode.cache.CacheListener; import org.apache.geode.cache.CustomExpiry; @@ -31,6 +33,7 @@ import org.apache.geode.cache.client.ClientRegionFactory; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.client.Pool; import org.apache.geode.compression.Compressor; +import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.InternalRegion; import org.apache.geode.internal.cache.UserSpecifiedRegionAttributes; @@ -220,7 +223,8 @@ public class ClientRegionFactoryImpl<K, V> implements ClientRegionFactory<K, V> @SuppressWarnings("deprecation") private RegionAttributes<K, V> createRegionAttributes() { RegionAttributes<K, V> ra = this.attrsFactory.create(); - if (isEmpty(ra.getPoolName())) { + if (isEmpty(ra.getPoolName()) + || Objects.equals(GemFireCacheImpl.DEFAULT_POOL_NAME, ra.getPoolName())) { UserSpecifiedRegionAttributes<K, V> ura = (UserSpecifiedRegionAttributes<K, V>) ra; if (ura.requiresPoolName) { Pool dp = getDefaultPool(); diff --git a/geode-core/src/main/java/org/apache/geode/cache/client/internal/InternalClientCache.java b/geode-core/src/main/java/org/apache/geode/cache/client/internal/InternalClientCache.java index 537d632..ce5e9ba 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/client/internal/InternalClientCache.java +++ b/geode-core/src/main/java/org/apache/geode/cache/client/internal/InternalClientCache.java @@ -28,7 +28,7 @@ public interface InternalClientCache extends ClientCache { void determineDefaultPool(); - Pool determineDefaultPool(PoolFactory poolFactory); + void validatePoolFactory(PoolFactory poolFactory); <K, V> Region<K, V> basicCreateRegion(String name, RegionAttributes<K, V> attrs) throws RegionExistsException, TimeoutException; diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java index f40e900..a441ffb 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java @@ -47,6 +47,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Properties; import java.util.ServiceLoader; import java.util.Set; @@ -280,6 +281,11 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "Cache.ASYNC_EVENT_LISTENERS"); /** + * Name of the default pool. + */ + public static final String DEFAULT_POOL_NAME = "DEFAULT"; + + /** * If true then when a delta is applied the size of the entry value will be recalculated. If false * (the default) then the size of the entry value is unchanged by a delta application. Not a final * so that tests can change this value. @@ -1146,14 +1152,13 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has * May return null (even on a client). */ @Override - public Pool getDefaultPool() { + public synchronized Pool getDefaultPool() { + if (this.defaultPool == null) { + determineDefaultPool(); + } return this.defaultPool; } - private void setDefaultPool(Pool value) { - this.defaultPool = value; - } - /** * Perform initialization, solve the early escaped reference problem by putting publishing * references to this instance in this method (vs. the constructor). @@ -1221,8 +1226,6 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has } } - this.poolFactory = null; - startColocatedJmxManagerLocator(); startMemcachedServer(); @@ -1384,7 +1387,6 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has String cacheXmlDescription = this.cacheConfig.getCacheXMLDescription(); if (url == null && cacheXmlDescription == null) { if (isClient()) { - determineDefaultPool(); initializeClientRegionShortcuts(this); } else { initializeRegionShortcuts(this); @@ -2843,32 +2845,51 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has return defaultPoolFactory; } + private Pool findFirstCompatiblePool(Map<String, Pool> pools) { + // act as if the default pool was configured + // and see if we can find an existing one that is compatible + PoolFactoryImpl pfi = (PoolFactoryImpl) createDefaultPF(); + for (Pool p : pools.values()) { + if (((PoolImpl) p).isCompatible(pfi.getPoolAttributes())) { + return p; + } + } + return null; + } + + private void addLocalHostAsServer(PoolFactory poolFactory) { + PoolFactoryImpl poolFactoryImpl = (PoolFactoryImpl) poolFactory; + if (poolFactoryImpl.getPoolAttributes().locators.isEmpty() + && poolFactoryImpl.getPoolAttributes().servers.isEmpty()) { + try { + String localHostName = SocketCreator.getHostName(SocketCreator.getLocalHost()); + poolFactoryImpl.addServer(localHostName, CacheServer.DEFAULT_PORT); + } catch (UnknownHostException ex) { + throw new IllegalStateException("Could not determine local host name", ex); + } + } + } + /** * Used to set the default pool on a new GemFireCache. */ - public void determineDefaultPool() { + public synchronized void determineDefaultPool() { if (!isClient()) { throw new UnsupportedOperationException(); } + PoolFactory defaultPoolFactory = this.poolFactory; + Pool pool = null; // create the pool if it does not already exist - if (this.poolFactory == null) { + if (defaultPoolFactory == null) { Map<String, Pool> pools = PoolManager.getAll(); if (pools.isEmpty()) { - this.poolFactory = createDefaultPF(); + defaultPoolFactory = createDefaultPF(); } else if (pools.size() == 1) { // otherwise use a singleton. pool = pools.values().iterator().next(); } else { - // act as if the default pool was configured - // and see if we can find an existing one that is compatible - PoolFactoryImpl pfi = (PoolFactoryImpl) createDefaultPF(); - for (Pool p : pools.values()) { - if (((PoolImpl) p).isCompatible(pfi.getPoolAttributes())) { - pool = p; - break; - } - } + pool = findFirstCompatiblePool(pools); if (pool == null) { // if pool is still null then we will not have a default pool for this ClientCache this.defaultPool = null; @@ -2876,21 +2897,15 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has } } } else { - PoolFactoryImpl pfi = (PoolFactoryImpl) this.poolFactory; - if (pfi.getPoolAttributes().locators.isEmpty() && pfi.getPoolAttributes().servers.isEmpty()) { - try { - String localHostName = SocketCreator.getHostName(SocketCreator.getLocalHost()); - pfi.addServer(localHostName, CacheServer.DEFAULT_PORT); - } catch (UnknownHostException ex) { - throw new IllegalStateException("Could not determine local host name", ex); - } - } + addLocalHostAsServer(defaultPoolFactory); + // look for a pool that already exists that is compatible with // our PoolFactory. // If we don't find one we will create a new one that meets our needs. Map<String, Pool> pools = PoolManager.getAll(); for (Pool p : pools.values()) { - if (((PoolImpl) p).isCompatible(pfi.getPoolAttributes())) { + if (((PoolImpl) p) + .isCompatible(((PoolFactoryImpl) defaultPoolFactory).getPoolAttributes())) { pool = p; break; } @@ -2898,75 +2913,29 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has } if (pool == null) { // create our pool with a unique name - String poolName = "DEFAULT"; + String poolName = DEFAULT_POOL_NAME; int count = 1; Map<String, Pool> pools = PoolManager.getAll(); while (pools.containsKey(poolName)) { - poolName = "DEFAULT" + count; + poolName = DEFAULT_POOL_NAME + count; count++; } - pool = this.poolFactory.create(poolName); + pool = defaultPoolFactory.create(poolName); } this.defaultPool = pool; } /** - * Used to see if a existing cache's pool is compatible with us. + * Determine whether the specified pool factory matches the pool factory used by this cache. * - * @return the default pool that is right for us + * @param poolFactory Prospective pool factory. + * @throws IllegalStateException When the specified pool factory does not match. */ - public Pool determineDefaultPool(PoolFactory poolFactory) { - Pool pool; - // create the pool if it does not already exist - if (poolFactory == null) { - Map<String, Pool> pools = PoolManager.getAll(); - if (pools.isEmpty()) { - throw new IllegalStateException("Since a cache already existed a pool should also exist."); - } else if (pools.size() == 1) { - // otherwise use a singleton. - pool = pools.values().iterator().next(); - if (getDefaultPool() != pool) { - throw new IllegalStateException( - "Existing cache's default pool was not the same as the only existing pool"); - } - } else { - // just use the current default pool if one exists - pool = getDefaultPool(); - if (pool == null) { - // act as if the default pool was configured - // and see if we can find an existing one that is compatible - PoolFactoryImpl pfi = (PoolFactoryImpl) createDefaultPF(); - for (Pool p : pools.values()) { - if (((PoolImpl) p).isCompatible(pfi.getPoolAttributes())) { - pool = p; - break; - } - } - if (pool == null) { - // if pool is still null then we will not have a default pool for this ClientCache - return null; - } - } - } - } else { - PoolFactoryImpl poolFactoryImpl = (PoolFactoryImpl) poolFactory; - if (poolFactoryImpl.getPoolAttributes().locators.isEmpty() - && poolFactoryImpl.getPoolAttributes().servers.isEmpty()) { - try { - String localHostName = SocketCreator.getHostName(SocketCreator.getLocalHost()); - poolFactoryImpl.addServer(localHostName, CacheServer.DEFAULT_PORT); - } catch (UnknownHostException ex) { - throw new IllegalStateException("Could not determine local host name", ex); - } - } - PoolImpl defaultPool = (PoolImpl) getDefaultPool(); - if (defaultPool != null && defaultPool.isCompatible(poolFactoryImpl.getPoolAttributes())) { - pool = defaultPool; - } else { - throw new IllegalStateException("Existing cache's default pool was not compatible"); - } + public void validatePoolFactory(PoolFactory poolFactory) { + // If the specified pool factory is null, by definition there is no pool factory to validate. + if (poolFactory != null && !Objects.equals(this.poolFactory, poolFactory)) { + throw new IllegalStateException("Existing cache's default pool was not compatible"); } - return pool; } @Override @@ -3048,6 +3017,11 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has } else if (isPartitionedRegion) { region = new PartitionedRegion(name, attrs, null, this, internalRegionArgs); } else { + // Abstract region depends on the default pool existing so lazily initialize it + // if necessary. + if (Objects.equals(attrs.getPoolName(), DEFAULT_POOL_NAME)) { + determineDefaultPool(); + } if (attrs.getScope().isLocal()) { region = new LocalRegion(name, attrs, null, this, internalRegionArgs); } else { diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/PoolFactoryImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/PoolFactoryImpl.java index 06f447f..6815bc7 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/PoolFactoryImpl.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/PoolFactoryImpl.java @@ -22,15 +22,15 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; -import java.util.Properties; +import java.util.Objects; import org.apache.logging.log4j.Logger; import org.apache.geode.DataSerializable; import org.apache.geode.DataSerializer; import org.apache.geode.cache.CacheException; -import org.apache.geode.cache.RegionService; import org.apache.geode.cache.client.Pool; import org.apache.geode.cache.client.PoolFactory; import org.apache.geode.cache.client.internal.LocatorDiscoveryCallback; @@ -354,6 +354,19 @@ public class PoolFactoryImpl implements PoolFactory { return this.attributes; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof PoolFactoryImpl)) { + return false; + } + PoolFactoryImpl that = (PoolFactoryImpl) o; + return Objects.equals(attributes, that.attributes) + && Objects.equals(new HashSet(locatorAddresses), new HashSet(that.locatorAddresses)); + } + /** * Not a true pool just the attributes. Serialization is used by unit tests */ @@ -608,5 +621,36 @@ public class PoolFactoryImpl implements PoolFactory { this.multiuserSecureModeEnabled = DataSerializer.readPrimitiveBoolean(in); this.socketConnectTimeout = DataSerializer.readPrimitiveInt(in); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof PoolAttributes)) { + return false; + } + PoolAttributes that = (PoolAttributes) o; + return socketConnectTimeout == that.socketConnectTimeout + && connectionTimeout == that.connectionTimeout + && connectionLifetime == that.connectionLifetime + && socketBufferSize == that.socketBufferSize + && threadLocalConnections == that.threadLocalConnections + && readTimeout == that.readTimeout && minConnections == that.minConnections + && maxConnections == that.maxConnections && idleTimeout == that.idleTimeout + && retryAttempts == that.retryAttempts && pingInterval == that.pingInterval + && statisticInterval == that.statisticInterval && queueEnabled == that.queueEnabled + && prSingleHopEnabled == that.prSingleHopEnabled + && queueRedundancyLevel == that.queueRedundancyLevel + && queueMessageTrackingTimeout == that.queueMessageTrackingTimeout + && queueAckInterval == that.queueAckInterval + && multiuserSecureModeEnabled == that.multiuserSecureModeEnabled + && startDisabled == that.startDisabled && gateway == that.gateway + && Objects.equals(serverGroup, that.serverGroup) + && Objects.equals(new HashSet(locators), new HashSet(that.locators)) + && Objects.equals(new HashSet(servers), new HashSet(that.servers)) + && Objects.equals(locatorCallback, that.locatorCallback) + && Objects.equals(gatewaySender, that.gatewaySender); + } } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ClientCacheCreation.java b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ClientCacheCreation.java index 8d03f42..ffee134 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ClientCacheCreation.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ClientCacheCreation.java @@ -196,8 +196,6 @@ public class ClientCacheCreation extends CacheCreation implements ClientCache { } } - cache.determineDefaultPool(); - if (hasResourceManager()) { // moved this up to fix bug 42128 getResourceManager().configure(cache.getResourceManager()); diff --git a/geode-core/src/test/java/org/apache/geode/cache/client/ClientCacheFactoryJUnitTest.java b/geode-core/src/test/java/org/apache/geode/cache/client/ClientCacheFactoryJUnitTest.java index f118741..c352a6c 100644 --- a/geode-core/src/test/java/org/apache/geode/cache/client/ClientCacheFactoryJUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/cache/client/ClientCacheFactoryJUnitTest.java @@ -330,6 +330,7 @@ public class ClientCacheFactoryJUnitTest { assertEquals( Collections.singletonList(new InetSocketAddress(InetAddress.getLocalHost(), 55555)), defPool.getServers()); + try { new ClientCacheFactory().addPoolServer(InetAddress.getLocalHost().getHostName(), 44444) .create(); diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java index aac6eea..27c9a62 100755 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java @@ -53,6 +53,7 @@ import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionEvent; import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.Scope; +import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.client.NoAvailableServersException; @@ -800,6 +801,9 @@ public class ClientServerMiscDUnitTest extends JUnit4CacheTestCase { clientCacheFactory.addPoolServer("localhost", DistributedTestUtils.getDUnitLocatorPort()); clientCacheFactory.setPoolSubscriptionEnabled(true); getClientCache(clientCacheFactory); + Region region = ((ClientCache) cache).createClientRegionFactory(ClientRegionShortcut.PROXY) + .create(REGION_NAME1); + region.registerInterest(k1); } diff --git a/geode-core/src/test/java/org/apache/geode/security/ClientAuthDUnitTest.java b/geode-core/src/test/java/org/apache/geode/security/ClientAuthDUnitTest.java index 0c6c710..06840cb 100644 --- a/geode-core/src/test/java/org/apache/geode/security/ClientAuthDUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/security/ClientAuthDUnitTest.java @@ -15,12 +15,17 @@ package org.apache.geode.security; import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_MANAGER; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import java.io.Serializable; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.apache.geode.cache.client.ClientCache; +import org.apache.geode.cache.client.ClientRegionFactory; +import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.test.dunit.IgnoredException; import org.apache.geode.test.dunit.rules.ClusterStartupRule; import org.apache.geode.test.junit.categories.DistributedTest; @@ -45,8 +50,25 @@ public class ClientAuthDUnitTest { public void authWithIncorrectPasswordShouldFail() throws Exception { IgnoredException.addIgnoredException(AuthenticationFailedException.class.getName()); - assertThatThrownBy( - () -> lsRule.startClientVM(0, "test", "invalidPassword", true, server.getPort())) + assertThatThrownBy(() -> lsRule.startClientVM(0, "test", "invalidPassword", true, + server.getPort(), new ClientCacheHook(lsRule))) .isInstanceOf(AuthenticationFailedException.class); } + + static class ClientCacheHook implements Runnable, Serializable { + final ClusterStartupRule lsRule; + + ClientCacheHook(ClusterStartupRule lsRule) { + this.lsRule = lsRule; + } + + public void run() { + // Perform an operation that causes the cache to lazy-initialize a pool with the invalid + // authentication so as to induce the exception. + ClientCache clientCache = lsRule.getClientCache(); + ClientRegionFactory clientRegionFactory = + clientCache.createClientRegionFactory(ClientRegionShortcut.PROXY); + clientRegionFactory.create("region"); + } + } } diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java index 297da02..23d6cc5 100644 --- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java +++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java @@ -36,8 +36,10 @@ import java.util.stream.Collectors; import org.junit.rules.ExternalResource; import org.junit.rules.TemporaryFolder; +import org.apache.geode.cache.Region; import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientCacheFactory; +import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.server.CacheServer; import org.apache.geode.distributed.internal.InternalLocator; import org.apache.geode.internal.AvailablePortHelper; @@ -325,12 +327,21 @@ public class ClusterStartupRule extends ExternalResource implements Serializable */ public ClientVM startClientVM(int index, Properties properties, Consumer<ClientCacheFactory> cacheFactorySetup, String clientVersion) throws Exception { + return startClientVM(index, properties, cacheFactorySetup, clientVersion, + (Runnable & Serializable) () -> { + }); + } + + public ClientVM startClientVM(int index, Properties properties, + Consumer<ClientCacheFactory> cacheFactorySetup, String clientVersion, + Runnable clientCacheHook) throws Exception { VM client = getVM(index, clientVersion); Exception error = client.invoke(() -> { clientCacheRule = new ClientCacheRule().withProperties(properties).withCacheSetup(cacheFactorySetup); try { clientCacheRule.before(); + clientCacheHook.run(); return null; } catch (Exception e) { return e; @@ -366,6 +377,20 @@ public class ClusterStartupRule extends ExternalResource implements Serializable return startClientVM(index, props, consumer); } + public ClientVM startClientVM(int index, String username, String password, + boolean subscriptionEnabled, int serverPort, Runnable clientCacheHook) throws Exception { + Properties props = new Properties(); + props.setProperty(UserPasswordAuthInit.USER_NAME, username); + props.setProperty(UserPasswordAuthInit.PASSWORD, password); + props.setProperty(SECURITY_CLIENT_AUTH_INIT, UserPasswordAuthInit.class.getName()); + + Consumer<ClientCacheFactory> consumer = + (Serializable & Consumer<ClientCacheFactory>) ((cacheFactory) -> { + cacheFactory.setPoolSubscriptionEnabled(subscriptionEnabled); + cacheFactory.addPoolServer("localhost", serverPort); + }); + return startClientVM(index, props, consumer, VersionManager.CURRENT_VERSION, clientCacheHook); + } /** * Returns the {@link Member} running inside the VM with the specified {@code index} -- To stop receiving notification emails like this one, please contact pivotalsa...@apache.org.