org.infinispan.client.hotrod.RemoteCacheManager Maven / Gradle / Ivy
package org.infinispan.client.hotrod;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.client.hotrod.configuration.Configuration;
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.configuration.NearCacheConfiguration;
import org.infinispan.client.hotrod.event.ClientListenerNotifier;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.client.hotrod.impl.InvalidatedNearRemoteCache;
import org.infinispan.client.hotrod.impl.RemoteCacheImpl;
import org.infinispan.client.hotrod.impl.operations.OperationsFactory;
import org.infinispan.client.hotrod.impl.operations.PingOperation.PingResult;
import org.infinispan.client.hotrod.impl.protocol.Codec;
import org.infinispan.client.hotrod.impl.protocol.CodecFactory;
import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
import org.infinispan.client.hotrod.impl.transport.TransportFactory;
import org.infinispan.client.hotrod.impl.transport.tcp.TcpTransportFactory;
import org.infinispan.client.hotrod.logging.Log;
import org.infinispan.client.hotrod.logging.LogFactory;
import org.infinispan.client.hotrod.near.NearCacheService;
import org.infinispan.commons.executors.ExecutorFactory;
import org.infinispan.commons.marshall.Marshaller;
import org.infinispan.commons.util.FileLookupFactory;
import org.infinispan.commons.util.Util;
import org.infinispan.commons.util.uberjar.ManifestUberJarDuplicatedJarsWarner;
import org.infinispan.commons.util.uberjar.UberJarDuplicatedJarsWarner;
/**
* Factory for {@link org.infinispan.client.hotrod.RemoteCache}s. Lifecycle:
In order to be able to
* use an {@link org.infinispan.client.hotrod.RemoteCache}, the {@link org.infinispan.client.hotrod.RemoteCacheManager}
* must be started first: beside other things, this instantiates connections to Hot Rod server(s). Starting the {@link
* org.infinispan.client.hotrod.RemoteCacheManager} can be done either at creation by passing start==true to constructor
* or by using a constructor that does that for you (see C-tor documentation); or after construction by calling {@link
* #start()}.
*
* This is an "expensive" object, as it manages a set of persistent TCP connections to the Hot Rod servers. It is recommended
* to only have one instance of this per JVM, and to cache it between calls to the server (i.e. remoteCache
* operations).
*
* {@link #stop()} needs to be called explicitly in order to release all the resources (e.g. threads, TCP connections).
*
*
* @author [email protected]
* @since 4.1
*/
public class RemoteCacheManager implements RemoteCacheContainer {
private static final Log log = LogFactory.getLog(RemoteCacheManager.class);
public static final String DEFAULT_CACHE_NAME = "___defaultcache";
public static final String HOTROD_CLIENT_PROPERTIES = "hotrod-client.properties";
private volatile boolean started = false;
private final Map cacheName2RemoteCache = new HashMap<>();
private final AtomicInteger defaultCacheTopologyId = new AtomicInteger(HotRodConstants.DEFAULT_CACHE_TOPOLOGY);
private Configuration configuration;
private Codec codec;
private Marshaller marshaller;
protected TransportFactory transportFactory;
private ExecutorService asyncExecutorService;
protected ClientListenerNotifier listenerNotifier;
/**
*
* Create a new RemoteCacheManager using the supplied {@link Configuration}.
* The RemoteCacheManager will be started automatically
*
* @param configuration the configuration to use for this RemoteCacheManager
* @since 5.3
*/
public RemoteCacheManager(Configuration configuration) {
this(configuration, true);
}
/**
*
* Create a new RemoteCacheManager using the supplied {@link Configuration}.
* The RemoteCacheManager will be started automatically only if the start parameter is true
*
* @param configuration the configuration to use for this RemoteCacheManager
* @param start whether or not to start the manager on return from the constructor.
* @since 5.3
*/
public RemoteCacheManager(Configuration configuration, boolean start) {
this.configuration = configuration;
if (start) start();
}
/**
* @since 5.3
*/
@Override
public Configuration getConfiguration() {
return configuration;
}
/**
* Same as {@link RemoteCacheManager(java.util.Properties)}, but it will try to lookup the config properties in the
* classpath, in a file named hotrod-client.properties. If no properties can be found in the classpath, the
* server tries to connect to "127.0.0.1:11222" in start.
*
* @param start whether or not to start the RemoteCacheManager
* @throws HotRodClientException if such a file cannot be found in the classpath
*/
public RemoteCacheManager(boolean start) {
ConfigurationBuilder builder = new ConfigurationBuilder();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
builder.classLoader(cl);
InputStream stream = FileLookupFactory.newInstance().lookupFile(HOTROD_CLIENT_PROPERTIES, cl);
if (stream == null) {
log.couldNotFindPropertiesFile(HOTROD_CLIENT_PROPERTIES);
} else {
try {
builder.withProperties(loadFromStream(stream));
} finally {
Util.close(stream);
}
}
this.configuration = builder.build();
if (start) start();
}
/**
* Same as {@link #RemoteCacheManager(boolean)} and it also starts the cache.
*/
public RemoteCacheManager() {
this(true);
}
/**
* Retrieves a named cache from the remote server if the cache has been
* defined, otherwise if the cache name is undefined, it will return null.
*
* @param cacheName name of cache to retrieve
* @return a cache instance identified by cacheName or null if the cache
* name has not been defined
*/
@Override
public RemoteCache getCache(String cacheName) {
return getCache(cacheName, configuration.forceReturnValues());
}
@Override
public RemoteCache getCache(String cacheName, boolean forceReturnValue) {
return createRemoteCache(cacheName, forceReturnValue);
}
/**
* Retrieves the default cache from the remote server.
*
* @return a remote cache instance that can be used to send requests to the
* default cache in the server
*/
@Override
public RemoteCache getCache() {
return getCache(configuration.forceReturnValues());
}
@Override
public RemoteCache getCache(boolean forceReturnValue) {
//As per the HotRod protocol specification, the default cache is identified by an empty string
return createRemoteCache("", forceReturnValue);
}
@Override
public void start() {
// Workaround for JDK6 NPE: http://bugs.sun.com/view_bug.do?bug_id=6427854
SecurityActions.setProperty("sun.nio.ch.bugLevel", "\"\"");
transportFactory = Util.getInstance(configuration.transportFactory());
if (marshaller == null) {
marshaller = configuration.marshaller();
if (marshaller == null) {
marshaller = Util.getInstance(configuration.marshallerClass());
}
}
codec = CodecFactory.getCodec(configuration.version());
if (asyncExecutorService == null) {
ExecutorFactory executorFactory = configuration.asyncExecutorFactory().factory();
if (executorFactory == null) {
executorFactory = Util.getInstance(configuration.asyncExecutorFactory().factoryClass());
}
asyncExecutorService = executorFactory.getExecutor(configuration.asyncExecutorFactory().properties());
}
listenerNotifier = ClientListenerNotifier.create(codec, marshaller, transportFactory);
transportFactory.start(codec, configuration, defaultCacheTopologyId, listenerNotifier);
synchronized (cacheName2RemoteCache) {
for (RemoteCacheHolder rcc : cacheName2RemoteCache.values()) {
startRemoteCache(rcc);
}
}
// Print version to help figure client version run
log.version(RemoteCacheManager.class.getPackage().getImplementationVersion());
warnAboutUberJarDuplicates();
started = true;
}
private final void warnAboutUberJarDuplicates() {
UberJarDuplicatedJarsWarner scanner = new ManifestUberJarDuplicatedJarsWarner();
scanner.isClasspathCorrectAsync()
.thenAcceptAsync(isClasspathCorrect -> {
if(!isClasspathCorrect)
log.warnAboutUberJarDuplicates();
});
}
/**
* Stop the remote cache manager, disconnecting all existing connections.
* As part of the disconnection, all registered client cache listeners will
* be removed since client no longer can receive callbacks.
*/
@Override
public void stop() {
if (isStarted()) {
listenerNotifier.stop();
transportFactory.destroy();
asyncExecutorService.shutdownNow();
}
started = false;
}
@Override
public boolean isStarted() {
return started;
}
@Override
public boolean switchToCluster(String clusterName) {
return transportFactory.switchToCluster(clusterName);
}
@Override
public boolean switchToDefaultCluster() {
return transportFactory.switchToCluster(TcpTransportFactory.DEFAULT_CLUSTER_NAME);
}
private Properties loadFromStream(InputStream stream) {
Properties properties = new Properties();
try {
properties.load(stream);
} catch (IOException e) {
throw new HotRodClientException("Issues configuring from client hotrod-client.properties", e);
}
return properties;
}
@SuppressWarnings("unchecked")
private RemoteCache createRemoteCache(String cacheName, Boolean forceReturnValueOverride) {
synchronized (cacheName2RemoteCache) {
RemoteCacheKey key = new RemoteCacheKey(cacheName, forceReturnValueOverride);
if (!cacheName2RemoteCache.containsKey(key)) {
RemoteCacheImpl result = createRemoteCache(cacheName);
RemoteCacheHolder rcc = new RemoteCacheHolder(result, forceReturnValueOverride == null ? configuration.forceReturnValues() : forceReturnValueOverride);
startRemoteCache(rcc);
PingResult pingResult = result.resolveCompatibility();
// If ping not successful assume that the cache does not exist
// Default cache is always started, so don't do for it
if (!cacheName.equals(RemoteCacheManager.DEFAULT_CACHE_NAME) &&
pingResult == PingResult.CACHE_DOES_NOT_EXIST) {
return null;
}
result.start();
// If ping on startup is disabled, or cache is defined in server
cacheName2RemoteCache.put(key, rcc);
return result;
} else {
return (RemoteCache) cacheName2RemoteCache.get(key).remoteCache;
}
}
}
private RemoteCacheImpl createRemoteCache(String cacheName) {
switch (configuration.nearCache().mode()) {
case INVALIDATED:
return new InvalidatedNearRemoteCache<>(this, cacheName,
createNearCacheService(configuration.nearCache()));
case DISABLED:
default:
return new RemoteCacheImpl<>(this, cacheName);
}
}
protected NearCacheService createNearCacheService(NearCacheConfiguration cfg) {
return NearCacheService.create(cfg, listenerNotifier);
}
private void startRemoteCache(RemoteCacheHolder remoteCacheHolder) {
RemoteCacheImpl, ?> remoteCache = remoteCacheHolder.remoteCache;
OperationsFactory operationsFactory = new OperationsFactory(
transportFactory, remoteCache.getName(), remoteCacheHolder.forceReturnValue, codec, listenerNotifier,
asyncExecutorService, configuration.clientIntelligence());
remoteCache.init(marshaller, asyncExecutorService, operationsFactory, configuration.keySizeEstimate(), configuration.valueSizeEstimate());
}
@Override
public Marshaller getMarshaller() {
return marshaller;
}
public static byte[] cacheNameBytes(String cacheName) {
return cacheName.equals(DEFAULT_CACHE_NAME)
? HotRodConstants.DEFAULT_CACHE_NAME_BYTES
: cacheName.getBytes(HotRodConstants.HOTROD_STRING_CHARSET);
}
public static byte[] cacheNameBytes() {
return HotRodConstants.DEFAULT_CACHE_NAME_BYTES;
}
}
class RemoteCacheKey {
final String cacheName;
final boolean forceReturnValue;
RemoteCacheKey(String cacheName, boolean forceReturnValue) {
this.cacheName = cacheName;
this.forceReturnValue = forceReturnValue;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RemoteCacheKey)) return false;
RemoteCacheKey that = (RemoteCacheKey) o;
if (forceReturnValue != that.forceReturnValue) return false;
return !(cacheName != null ? !cacheName.equals(that.cacheName) : that.cacheName != null);
}
@Override
public int hashCode() {
int result = cacheName != null ? cacheName.hashCode() : 0;
result = 31 * result + (forceReturnValue ? 1 : 0);
return result;
}
}
class RemoteCacheHolder {
final RemoteCacheImpl, ?> remoteCache;
final boolean forceReturnValue;
RemoteCacheHolder(RemoteCacheImpl, ?> remoteCache, boolean forceReturnValue) {
this.remoteCache = remoteCache;
this.forceReturnValue = forceReturnValue;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy