Infinispan 15.0.3.Final

Closes #29068

Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
Pedro Ruivo 2024-04-13 18:38:33 +01:00 committed by Alexander Schwartz
parent 8ff1ae0c08
commit cbce548e71
32 changed files with 170 additions and 303 deletions

View file

@ -92,16 +92,12 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View file

@ -88,11 +88,6 @@
<groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId>
</dependency>
<dependency>
<!-- adding it explictly, as Keycloak's parent excludes it to have full control over Jakarta EE vs. Java EE -->
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View file

@ -16,6 +16,14 @@
*/
package org.keycloak.adapters.saml.elytron.infinispan;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore;
import org.jboss.logging.Logger;
import org.keycloak.adapters.saml.AdapterConstants;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapperUpdater;
@ -23,14 +31,6 @@ import org.keycloak.adapters.spi.SessionIdMapperUpdater;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore;
import org.jboss.logging.Logger;
import java.util.Set;
/**
@ -94,21 +94,19 @@ public class InfinispanSessionCacheIdMapperUpdater {
}
Cache<String, String[]> ssoCache = cacheManager.getCache(cacheName, true);
final SsoSessionCacheListener listener = new SsoSessionCacheListener(ssoCache, mapper);
SsoSessionCacheListener listener = new SsoSessionCacheListener(ssoCache, mapper);
ssoCache.addListener(listener);
addSsoCacheCrossDcListener(ssoCache, listener);
LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, cacheName);
SsoCacheSessionIdMapperUpdater updater = new SsoCacheSessionIdMapperUpdater(ssoCache, previousIdMapperUpdater) {
return new SsoCacheSessionIdMapperUpdater(ssoCache, previousIdMapperUpdater) {
@Override
public void close() throws Exception {
public void close() {
ssoCache.stop();
}
};
return updater;
} catch (NamingException ex) {
LOG.warnv("Failed to obtain distributed session cache container, lookup={0}", cacheContainerLookup);
return previousIdMapperUpdater;
@ -137,7 +135,7 @@ public class InfinispanSessionCacheIdMapperUpdater {
return;
}
final Set<RemoteStore> stores = getRemoteStores(ssoCache);
Set<RemoteStore> stores = getRemoteStores(ssoCache);
if (stores == null || stores.isEmpty()) {
return;
}
@ -149,7 +147,7 @@ public class InfinispanSessionCacheIdMapperUpdater {
}
}
public static Set<RemoteStore> getRemoteStores(Cache ispnCache) {
return ispnCache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class);
public static Set<RemoteStore> getRemoteStores(Cache<?, ?> ispnCache) {
return ComponentRegistry.componentOf(ispnCache, PersistenceManager.class).getStores(RemoteStore.class);
}
}

View file

@ -224,7 +224,7 @@ spec:
expose:
type: Route
configMapName: "cluster-config"
image: quay.io/infinispan/server:14.0.27.Final
image: quay.io/infinispan/server:15.0.3.Final
configListener:
enabled: false
container:

View file

@ -363,7 +363,7 @@ spec:
expose:
type: Route
configMapName: "cluster-config"
image: quay.io/infinispan/server:14.0.27.Final
image: quay.io/infinispan/server:15.0.3.Final
configListener:
enabled: false
container:

View file

@ -363,7 +363,7 @@ spec:
expose:
type: Route
configMapName: "cluster-config"
image: quay.io/infinispan/server:14.0.27.Final
image: quay.io/infinispan/server:15.0.3.Final
configListener:
enabled: false
container:

View file

@ -59,11 +59,7 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>

View file

@ -20,13 +20,11 @@ package org.keycloak.cluster.infinispan;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged;
import org.infinispan.notifications.cachemanagerlistener.event.ViewChangedEvent;
import org.infinispan.persistence.remote.RemoteStore;
import org.infinispan.remoting.transport.Address;
import org.infinispan.remoting.transport.Transport;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.cluster.ClusterProvider;
@ -35,10 +33,10 @@ import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.connections.infinispan.InfinispanUtil;
import java.io.Serializable;
import java.util.Collection;
@ -47,7 +45,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@ -72,7 +69,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
// Just to extract notifications related stuff to separate class
private InfinispanNotificationsManager notificationsManager;
private ExecutorService localExecutor = Executors.newCachedThreadPool(r -> {
private final ExecutorService localExecutor = Executors.newCachedThreadPool(r -> {
Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setName(this.getClass().getName() + "-" + thread.getName());
return thread;
@ -140,7 +137,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
static <V extends Serializable> V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) {
AtomicReference<V> resultRef = new AtomicReference<>();
Retry.executeWithBackoff((int iteration) -> {
Retry.executeWithBackoff(iteration -> {
try {
V result;
@ -196,17 +193,14 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
@ViewChanged
public void viewChanged(ViewChangedEvent event) {
final Set<String> removedNodesAddresses = convertAddresses(event.getOldMembers());
final Set<String> newAddresses = convertAddresses(event.getNewMembers());
Set<String> removedNodesAddresses = convertAddresses(event.getOldMembers());
Set<String> newAddresses = convertAddresses(event.getNewMembers());
// Use separate thread to avoid potential deadlock
localExecutor.execute(() -> {
try {
EmbeddedCacheManager cacheManager = workCache.getCacheManager();
Transport transport = cacheManager.getTransport();
// Coordinator makes sure that entries for outdated nodes are cleaned up
if (transport != null && transport.isCoordinator()) {
if (workCache.getCacheManager().isCoordinator()) {
removedNodesAddresses.removeAll(newAddresses);
@ -230,14 +224,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
}
private Set<String> convertAddresses(Collection<Address> addresses) {
return addresses.stream().map(new Function<Address, String>() {
@Override
public String apply(Address address) {
return address.toString();
}
}).collect(Collectors.toSet());
return addresses.stream().map(Object::toString).collect(Collectors.toSet());
}
}

View file

@ -18,6 +18,7 @@
package org.keycloak.connections.infinispan;
import org.infinispan.Cache;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.persistence.manager.PersistenceManager;
import org.jboss.logging.Logger;
import org.keycloak.health.LoadBalancerCheckProvider;
@ -60,9 +61,7 @@ public class InfinispanMultiSiteLoadBalancerCheckProvider implements LoadBalance
return true; // no need to check other caches
}
PersistenceManager persistenceManager = cache.getAdvancedCache()
.getComponentRegistry()
.getComponent(PersistenceManager.class);
var persistenceManager = ComponentRegistry.componentOf(cache, PersistenceManager.class);
if (persistenceManager != null && !persistenceManager.isAvailable()) {
LOG.debugf("PersistenceManager for cache '%s' is down.", cacheName);

View file

@ -17,11 +17,6 @@
package org.keycloak.connections.infinispan;
import java.time.Instant;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.ProtocolVersion;
import org.infinispan.client.hotrod.RemoteCache;
@ -34,7 +29,7 @@ import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.configuration.global.TransportConfigurationBuilder;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.eviction.EvictionType;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.factories.GlobalComponentRegistry;
import org.infinispan.factories.impl.BasicComponentRegistry;
import org.infinispan.factories.impl.ComponentRef;
@ -48,6 +43,11 @@ import org.jgroups.JChannel;
import org.keycloak.common.util.Time;
import org.keycloak.models.KeycloakSession;
import java.time.Instant;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@ -58,12 +58,12 @@ public class InfinispanUtil {
public static final int MAXIMUM_REPLACE_RETRIES = 25;
// See if we have RemoteStore (external JDG) configured for cross-Data-Center scenario
public static Set<RemoteStore> getRemoteStores(Cache ispnCache) {
return ispnCache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class);
public static Set<RemoteStore> getRemoteStores(Cache<?, ?> ispnCache) {
return ComponentRegistry.componentOf(ispnCache, PersistenceManager.class).getStores(RemoteStore.class);
}
public static RemoteCache getRemoteCache(Cache ispnCache) {
public static RemoteCache getRemoteCache(Cache<?, ?> ispnCache) {
Set<RemoteStore> remoteStores = getRemoteStores(ispnCache);
if (remoteStores.isEmpty()) {
return null;
@ -88,10 +88,9 @@ public class InfinispanUtil {
* @param lifespanOrigMs
* @return
*/
public static long toHotrodTimeMs(BasicCache ispnCache, long lifespanOrigMs) {
if (ispnCache instanceof RemoteCache && lifespanOrigMs > 2592000000L) {
RemoteCache remoteCache = (RemoteCache) ispnCache;
ProtocolVersion protocolVersion = remoteCache.getRemoteCacheManager().getConfiguration().version();
public static long toHotrodTimeMs(BasicCache<?, ?> ispnCache, long lifespanOrigMs) {
if (ispnCache instanceof RemoteCache<?, ?> remoteCache && lifespanOrigMs > 2592000000L) {
ProtocolVersion protocolVersion = remoteCache.getRemoteCacheContainer().getConfiguration().version();
if (ProtocolVersion.PROTOCOL_VERSION_30.compareTo(protocolVersion) > 0) {
return Time.currentTimeMillis() + lifespanOrigMs;
}
@ -166,9 +165,8 @@ public class InfinispanUtil {
ConfigurationBuilder cb = createCacheConfigurationBuilder();
cb.memory()
.evictionStrategy(EvictionStrategy.NONE)
.evictionType(EvictionType.COUNT)
.size(InfinispanConnectionProvider.ACTION_TOKEN_CACHE_DEFAULT_MAX);
.whenFull(EvictionStrategy.MANUAL)
.maxCount(InfinispanConnectionProvider.ACTION_TOKEN_CACHE_DEFAULT_MAX);
cb.expiration()
.maxIdle(InfinispanConnectionProvider.ACTION_TOKEN_MAX_IDLE_SECONDS, TimeUnit.SECONDS)
.wakeUpInterval(InfinispanConnectionProvider.ACTION_TOKEN_WAKE_UP_INTERVAL_SECONDS, TimeUnit.SECONDS);
@ -209,7 +207,7 @@ public class InfinispanUtil {
* @return the original component that was replaced
*/
private static <T> T replaceComponent(EmbeddedCacheManager cacheMgr, Class<T> componentType, T replacementComponent, boolean rewire) {
GlobalComponentRegistry cr = cacheMgr.getGlobalComponentRegistry();
GlobalComponentRegistry cr = GlobalComponentRegistry.of(cacheMgr);
BasicComponentRegistry bcr = cr.getComponent(BasicComponentRegistry.class);
ComponentRef<T> old = bcr.getComponent(componentType);
bcr.replaceComponent(componentType.getName(), replacementComponent, true);

View file

@ -17,12 +17,9 @@
package org.keycloak.connections.infinispan;
import java.net.InetSocketAddress;
import java.security.SecureRandom;
import java.util.Objects;
import org.infinispan.Cache;
import org.infinispan.distribution.DistributionManager;
import org.infinispan.factories.GlobalComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.remoting.transport.Address;
import org.infinispan.remoting.transport.LocalModeAddress;
@ -30,12 +27,14 @@ import org.infinispan.remoting.transport.Transport;
import org.infinispan.remoting.transport.jgroups.JGroupsAddress;
import org.infinispan.remoting.transport.jgroups.JGroupsTransport;
import org.jboss.logging.Logger;
import org.jgroups.Event;
import org.jgroups.JChannel;
import org.jgroups.stack.IpAddress;
import org.jgroups.util.NameCache;
import org.keycloak.Config;
import java.net.InetSocketAddress;
import java.security.SecureRandom;
import java.util.Objects;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@ -66,9 +65,9 @@ public class TopologyInfo {
}
if (!embedded) {
Transport transport = cacheManager.getTransport();
if (transport != null) {
nodeName = transport.getAddress().toString();
var addr = cacheManager.getAddress();
if (addr != null) {
nodeName = addr.toString();
siteName = cacheManager.getCacheManagerConfiguration().transport().siteId();
if (siteName == null) {
siteName = config.get("siteName");
@ -133,7 +132,7 @@ public class TopologyInfo {
/**
* True if I am primary owner of the key in case of distributed caches. In case of local caches, always return true
*/
public boolean amIOwner(Cache cache, Object key) {
public boolean amIOwner(Cache<?, ?> cache, Object key) {
Address myAddress = cache.getCacheManager().getAddress();
Address objectOwnerAddress = getOwnerAddress(cache, key);
@ -145,7 +144,7 @@ public class TopologyInfo {
/**
* Get route to be used as the identifier for sticky session. Return null if I am not able to find the appropriate route (or in case of local mode)
*/
public String getRouteName(Cache cache, Object key) {
public String getRouteName(Cache<?, ?> cache, Object key) {
if (cache.getCacheConfiguration().clustering().cacheMode().isClustered() && isGeneratedNodeName) {
logger.warn("Clustered configuration used, but node name is not properly set. Make sure to start server with jboss.node.name property identifying cluster node");
}
@ -168,11 +167,11 @@ public class TopologyInfo {
// If no logical name exists, create one using physical address
if (name == null) {
Transport transport = cache.getCacheManager().getTransport();
JChannel jgroupsChannel = ((JGroupsTransport) transport).getChannel();
IpAddress ipAddress = (IpAddress) jgroupsChannel.down(new Event(Event.GET_PHYSICAL_ADDRESS, jgroupsAddress));
// Physical address might be null if node is no longer a member of the cluster
var transport = GlobalComponentRegistry.componentOf(cache.getCacheManager(), Transport.class);
var channel = ((JGroupsTransport) transport).getChannel();
var ipAddress = (IpAddress) channel.getProtocolStack().getTransport().localPhysicalAddress();
// Physical address might be null if node is no longer a member of the cluster.
// This seems broken, it is returning the IP/PORT for JGroups!?
InetSocketAddress socketAddress = (ipAddress != null) ? new InetSocketAddress(ipAddress.getIpAddress(), ipAddress.getPort()) : new InetSocketAddress(0);
name = String.format("%s:%s", socketAddress.getHostString(), socketAddress.getPort());
@ -183,21 +182,16 @@ public class TopologyInfo {
}
private Address getOwnerAddress(Cache cache, Object key) {
private Address getOwnerAddress(Cache<?, ?> cache, Object key) {
DistributionManager dist = cache.getAdvancedCache().getDistributionManager();
Address address = (dist != null) && !cache.getCacheConfiguration().clustering().cacheMode().isScattered() ?
dist.getCacheTopology().getDistribution(key).primary() :
cache.getCacheManager().getAddress();
return address;
return dist == null ? cache.getCacheManager().getAddress() : dist.getCacheTopology().getDistribution(key).primary();
}
// See org.wildfly.clustering.server.group.CacheGroup
private static org.jgroups.Address toJGroupsAddress(Address address) {
if ((address == null) || (address == LocalModeAddress.INSTANCE)) return null;
if (address instanceof JGroupsAddress) {
JGroupsAddress jgroupsAddress = (JGroupsAddress) address;
if (address instanceof JGroupsAddress jgroupsAddress) {
return jgroupsAddress.getJGroupsAddress();
}
throw new IllegalArgumentException(address.toString());

View file

@ -202,11 +202,8 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
initializer.initCache();
initializer.loadSessions();
}
});
log.debugf("Pre-loading login failures from remote cache '%s' finished", cacheName);

View file

@ -399,11 +399,8 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
initializer.initCache();
initializer.loadSessions();
}
});
log.debugf("Pre-loading sessions from remote cache '%s' finished", cacheName);

View file

@ -17,15 +17,14 @@
package org.keycloak.models.sessions.infinispan.initializer;
import java.io.Serializable;
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.remoting.transport.Transport;
import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSessionFactory;
import java.io.Serializable;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@ -74,21 +73,15 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
}
protected void saveStateToCache(final InitializerState state) {
protected void saveStateToCache(InitializerState state) {
// 3 attempts to send the message (it may fail if some node fails in the meantime)
retry(3, new Runnable() {
@Override
public void run() {
retry(3, () -> {
// Save this synchronously to ensure all nodes read correct state
// We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored.
BaseCacheInitializer.this.workCache.getAdvancedCache().
withFlags(Flag.IGNORE_RETURN_VALUES, Flag.FORCE_SYNCHRONOUS, Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD)
.put(stateKey, state);
}
});
}

View file

@ -18,7 +18,6 @@
package org.keycloak.models.sessions.infinispan.initializer;
import org.infinispan.Cache;
import org.infinispan.factories.ComponentRegistry;
import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
@ -26,9 +25,9 @@ import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.io.Serializable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Startup initialization for reading persistent userSessions to be filled into infinispan/memory.
@ -53,18 +52,6 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
}
public void initCache() {
// due to lazy initialization, this might be called from multiple threads simultaneously, therefore, synchronize
synchronized (workCache) {
final ComponentRegistry cr = this.workCache.getAdvancedCache().getComponentRegistry();
// first check if already set, as Infinispan would otherwise throw a RuntimeException
if (cr.getComponent(KeycloakSessionFactory.class) != sessionFactory) {
cr.registerComponent(sessionFactory, KeycloakSessionFactory.class);
}
}
}
// Just coordinator will run this
@Override
protected void startLoading() {
@ -102,7 +89,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
}
protected void startLoadingImpl(InitializerState state, SessionLoader.LoaderContext loaderCtx) {
int errors = 0;
final int errors = 0;
int segmentToLoad = 0;
int distributedWorkersCount = 1;
@ -117,7 +104,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
log.trace("unfinished segments for this iteration: " + segments);
}
final Queue<SessionLoader.WorkerResult> results = new ConcurrentLinkedQueue<>();
Queue<SessionLoader.WorkerResult> results = new ConcurrentLinkedQueue<>();
for (Integer segment : segments) {
SessionLoader.WorkerContext workerCtx = sessionLoader.computeWorkerContext(segment);

View file

@ -17,11 +17,6 @@
package org.keycloak.cluster.infinispan;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.Flag;
import org.infinispan.client.hotrod.RemoteCache;
@ -31,12 +26,17 @@ import org.infinispan.client.hotrod.annotation.ClientListener;
import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent;
import org.infinispan.client.hotrod.event.ClientCacheEntryModifiedEvent;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore;
import org.infinispan.persistence.remote.configuration.RemoteStoreConfigurationBuilder;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Test concurrency for remoteStore (backed by HotRod RemoteCaches) against external JDG. Especially tests "putIfAbsent" contract.
*
@ -46,11 +46,7 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
*/
public class ConcurrencyJDGCachePutTest {
private static Map<String, EntryInfo> state = new HashMap<>();
private RemoteCache remoteCache1;
private RemoteCache remoteCache2;
private static final Map<String, EntryInfo> state = new HashMap<>();
public static void main(String[] args) throws Exception {
// Init map somehow
@ -105,7 +101,8 @@ public class ConcurrencyJDGCachePutTest {
System.out.println("Retrieved cache: " + threadId);
RemoteStore remoteStore = cache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class).iterator().next();
RemoteStore<?, ?> remoteStore = ComponentRegistry.componentOf(cache, PersistenceManager.class)
.getStores(RemoteStore.class).iterator().next();
HotRodListener listener = new HotRodListener();
remoteStore.getRemoteCache().addClientListener(listener);
@ -119,14 +116,14 @@ public class ConcurrencyJDGCachePutTest {
//private AtomicInteger listenerCount = new AtomicInteger(0);
@ClientCacheEntryCreated
public void created(ClientCacheEntryCreatedEvent event) {
String cacheKey = (String) event.getKey();
public void created(ClientCacheEntryCreatedEvent<String> event) {
String cacheKey = event.getKey();
state.get(cacheKey).successfulListenerWrites.incrementAndGet();
}
@ClientCacheEntryModified
public void updated(ClientCacheEntryModifiedEvent event) {
String cacheKey = (String) event.getKey();
public void updated(ClientCacheEntryModifiedEvent<String> event) {
String cacheKey = event.getKey();
state.get(cacheKey).successfulListenerWrites.incrementAndGet();
}
@ -171,7 +168,10 @@ public class ConcurrencyJDGCachePutTest {
//Integer existingClusterStartTime = (Integer) cache.putIfAbsent(cacheKey, startupTime);
// Concurrency works fine with this
RemoteCache remoteCache = cache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class).iterator().next().getRemoteCache();
RemoteCache remoteCache = ComponentRegistry.componentOf(cache, PersistenceManager.class)
.getStores(RemoteStore.class)
.iterator().next()
.getRemoteCache();
Integer existingClusterStartTime = null;
for (int i=0 ; i<10 ; i++) {

View file

@ -17,12 +17,6 @@
package org.keycloak.cluster.infinispan;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.VersionedValue;
@ -31,6 +25,7 @@ import org.infinispan.client.hotrod.annotation.ClientCacheEntryModified;
import org.infinispan.client.hotrod.annotation.ClientListener;
import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent;
import org.infinispan.client.hotrod.event.ClientCacheEntryModifiedEvent;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore;
@ -39,6 +34,12 @@ import org.junit.Assert;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Test that hotrod ClientListeners are correctly executed as expected
*
@ -68,11 +69,11 @@ import org.keycloak.connections.infinispan.InfinispanUtil;
public class ConcurrencyJDGRemoteCacheClientListenersTest {
// Helper map to track if listeners were executed
private static Map<String, EntryInfo> state = new HashMap<>();
private static final Map<String, EntryInfo> state = new HashMap<>();
private static AtomicInteger totalListenerCalls = new AtomicInteger(0);
private static final AtomicInteger totalListenerCalls = new AtomicInteger(0);
private static AtomicInteger totalErrors = new AtomicInteger(0);
private static final AtomicInteger totalErrors = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
@ -134,7 +135,8 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest {
System.out.println("Retrieved cache: " + threadId);
RemoteStore remoteStore = cache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class).iterator().next();
RemoteStore<?, ?> remoteStore = ComponentRegistry.componentOf(cache, PersistenceManager.class)
.getStores(RemoteStore.class).iterator().next();
HotRodListener listener = new HotRodListener(cache, threadId);
remoteStore.getRemoteCache().addClientListener(listener);
@ -147,7 +149,7 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest {
private final RemoteCache<String, Integer> remoteCache;
private final int threadId;
private Executor executor;
private final Executor executor;
public HotRodListener(Cache<String, Integer> cache, int threadId) {
this.remoteCache = InfinispanUtil.getRemoteCache(cache);
@ -158,26 +160,15 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest {
//private AtomicInteger listenerCount = new AtomicInteger(0);
@ClientCacheEntryCreated
public void created(ClientCacheEntryCreatedEvent event) {
String cacheKey = (String) event.getKey();
executor.execute(() -> {
event(cacheKey, event.getVersion(), true);
});
public void created(ClientCacheEntryCreatedEvent<String> event) {
executor.execute(() -> event(event.getKey(), event.getVersion(), true));
}
@ClientCacheEntryModified
public void updated(ClientCacheEntryModifiedEvent event) {
String cacheKey = (String) event.getKey();
executor.execute(() -> {
event(cacheKey, event.getVersion(), false);
});
public void updated(ClientCacheEntryModifiedEvent<String> event) {
executor.execute(() -> event(event.getKey(), event.getVersion(), false));
}

View file

@ -17,19 +17,11 @@
package org.keycloak.keys.infinispan;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.eviction.EvictionType;
import org.infinispan.manager.DefaultCacheManager;
import org.junit.After;
import org.junit.Assert;
@ -40,12 +32,19 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.crypto.PublicKeysWrapper;
import org.keycloak.keys.PublicKeyLoader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class InfinispanKeyStorageProviderTest {
private Map<String, AtomicInteger> counters = new ConcurrentHashMap<>();
private final Map<String, AtomicInteger> counters = new ConcurrentHashMap<>();
Cache<String, PublicKeysEntry> keys = getKeysCache();
Map<String, FutureTask<PublicKeysEntry>> tasksInProgress = new ConcurrentHashMap<>();
@ -157,14 +156,13 @@ public class InfinispanKeyStorageProviderTest {
protected Cache<String, PublicKeysEntry> getKeysCache() {
GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
gcb.jmx().domain(InfinispanConnectionProvider.JMX_DOMAIN).enable();
final DefaultCacheManager cacheManager = new DefaultCacheManager(gcb.build());
DefaultCacheManager cacheManager = new DefaultCacheManager(gcb.build());
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.memory()
.evictionStrategy(EvictionStrategy.REMOVE)
.evictionType(EvictionType.COUNT)
.size(InfinispanConnectionProvider.KEYS_CACHE_DEFAULT_MAX);
cb.jmxStatistics().enabled(true);
.whenFull(EvictionStrategy.REMOVE)
.maxCount(InfinispanConnectionProvider.KEYS_CACHE_DEFAULT_MAX);
cb.statistics().enabled(true);
Configuration cfg = cb.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.KEYS_CACHE_NAME, cfg);

View file

@ -18,8 +18,8 @@
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd"
xmlns="urn:infinispan:config:14.0">
xsi:schemaLocation="urn:infinispan:config:15.0 http://www.infinispan.org/schemas/infinispan-config-15.0.xsd"
xmlns="urn:infinispan:config:15.0">
<cache-container name="keycloak">
<transport lock-timeout="60000"/>

38
pom.xml
View file

@ -93,7 +93,7 @@
<h2.version>2.2.224</h2.version>
<hibernate-orm.plugin.version>6.2.13.Final</hibernate-orm.plugin.version>
<hibernate.c3p0.version>6.2.13.Final</hibernate.c3p0.version>
<infinispan.version>14.0.27.Final</infinispan.version>
<infinispan.version>15.0.3.Final</infinispan.version>
<!--JAKARTA-->
<jakarta.mail.version>2.1.1</jakarta.mail.version>
@ -311,42 +311,6 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-jboss-marshalling</artifactId>
<version>${infinispan.version}</version>
<exclusions>
<!-- this conflicts with infinispan-*-jakarta -->
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-commons</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId>
<version>${infinispan.version}</version>
<exclusions>
<!-- this conflicts with infinispan-*-jakarta -->
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-commons</artifactId>
</exclusion>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId>

View file

@ -38,7 +38,7 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-commons-jakarta</artifactId>
<artifactId>infinispan-commons</artifactId>
</dependency>
</dependencies>

View file

@ -457,19 +457,9 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-cachestore-remote</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.ua-parser</groupId>
@ -558,11 +548,11 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-commons-jakarta</artifactId>
<artifactId>infinispan-commons</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>

View file

@ -18,8 +18,8 @@
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd"
xmlns="urn:infinispan:config:14.0">
xsi:schemaLocation="urn:infinispan:config:15.0 http://www.infinispan.org/schemas/infinispan-config-15.0.xsd"
xmlns="urn:infinispan:config:15.0">
<cache-container name="keycloak">
<transport lock-timeout="60000"/>

View file

@ -18,8 +18,8 @@
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd"
xmlns="urn:infinispan:config:14.0">
xsi:schemaLocation="urn:infinispan:config:15.0 http://www.infinispan.org/schemas/infinispan-config-15.0.xsd"
xmlns="urn:infinispan:config:15.0">
<cache-container name="keycloak">
<local-cache name="default">

View file

@ -21,9 +21,9 @@
<!--tag::keycloak-ispn-configmap[] -->
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 https://www.infinispan.org/schemas/infinispan-config-14.0.xsd
urn:infinispan:config:store:remote:14.0 https://www.infinispan.org/schemas/infinispan-cachestore-remote-config-14.0.xsd"
xmlns="urn:infinispan:config:14.0">
xsi:schemaLocation="urn:infinispan:config:15.0 https://www.infinispan.org/schemas/infinispan-config-15.0.xsd
urn:infinispan:config:store:remote:15.0 https://www.infinispan.org/schemas/infinispan-cachestore-remote-config-15.0.xsd"
xmlns="urn:infinispan:config:15.0">
<!--end::keycloak-ispn-configmap[] -->
<!-- the statistics="true" attribute is not part of the original KC config and was added by Keycloak Benchmark -->
@ -47,8 +47,8 @@
<!--tag::keycloak-ispn-remotestore[] -->
<distributed-cache name="sessions" owners="2" statistics="true">
<expiration lifespan="-1"/>
<persistence passivation="false"> <!--1-->
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500"> <!--1-->
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="sessions"
raw-values="true"
shared="true"
@ -71,8 +71,8 @@
<!--end::keycloak-ispn-remotestore[] -->
<distributed-cache name="authenticationSessions" owners="2" statistics="true">
<expiration lifespan="-1"/>
<persistence passivation="false">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="authenticationSessions"
raw-values="true"
shared="true"
@ -94,8 +94,8 @@
</distributed-cache>
<distributed-cache name="offlineSessions" owners="2" statistics="true">
<expiration lifespan="-1"/>
<persistence passivation="false">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="offlineSessions"
raw-values="true"
shared="true"
@ -117,8 +117,8 @@
</distributed-cache>
<distributed-cache name="clientSessions" owners="2" statistics="true">
<expiration lifespan="-1"/>
<persistence passivation="false">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="clientSessions"
raw-values="true"
shared="true"
@ -140,8 +140,8 @@
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="2" statistics="true">
<expiration lifespan="-1"/>
<persistence passivation="false">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="offlineClientSessions"
raw-values="true"
shared="true"
@ -163,8 +163,8 @@
</distributed-cache>
<distributed-cache name="loginFailures" owners="2" statistics="true">
<expiration lifespan="-1"/>
<persistence passivation="false">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="loginFailures"
raw-values="true"
shared="true"
@ -193,8 +193,8 @@
</local-cache>
<replicated-cache name="work" statistics="true">
<expiration lifespan="-1"/>
<persistence passivation="false">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="work"
raw-values="true"
shared="true"
@ -229,8 +229,8 @@
</encoding>
<expiration max-idle="-1" lifespan="-1" interval="300000"/>
<memory max-count="-1"/>
<persistence passivation="false">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
<persistence passivation="false" availability-interval="500">
<remote-store xmlns="urn:infinispan:config:store:remote:15.0"
cache="actionTokens"
raw-values="true"
shared="true"

View file

@ -86,21 +86,11 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod-jakarta</artifactId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-tasks-api</artifactId>
<exclusions>
<exclusion>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

View file

@ -48,14 +48,14 @@ public class InfinispanTimeServiceTask implements ServerTask<String> {
@Override
public String call() {
EmbeddedCacheManager cacheManager = context.getCacheManager();
Map<String, Object> params = new HashMap();
Map<String, Object> params = new HashMap<>();
if (this.context.getParameters().isPresent())
params = this.context.getParameters().get();
if (params.containsKey("timeService")) {
offset = (int) params.get("timeService");
// rewire the Time service
GlobalComponentRegistry cr = cacheManager.getGlobalComponentRegistry();
GlobalComponentRegistry cr = GlobalComponentRegistry.of(cacheManager);
BasicComponentRegistry bcr = cr.getComponent(BasicComponentRegistry.class);
bcr.replaceComponent(TimeService.class.getName(), KEYCLOAK_TIME_SERVICE, true);
cr.rewire();

View file

@ -17,29 +17,28 @@
package org.keycloak.testsuite.rest.resource;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.stream.CacheCollectors;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.utils.MediaType;
import org.infinispan.stream.CacheCollectors;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -114,12 +113,10 @@ public class TestCacheResource {
@Path("/remote-cache-stats")
@Produces(MediaType.APPLICATION_JSON)
public Map<String, String> getRemoteCacheStats() {
RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache);
if (remoteCache == null) {
return new HashMap<>();
} else {
return remoteCache.stats().getStatsMap();
}
var remoteCache = InfinispanUtil.getRemoteCache(cache);
return remoteCache == null ?
Collections.emptyMap() :
remoteCache.serverStatistics().getStatsMap();
}
@ -127,11 +124,11 @@ public class TestCacheResource {
@Path("/remote-cache-last-session-refresh/{user-session-id}")
@Produces(MediaType.APPLICATION_JSON)
public int getRemoteCacheLastSessionRefresh(@PathParam("user-session-id") String userSessionId) {
RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache);
RemoteCache<String, SessionEntityWrapper<UserSessionEntity>> remoteCache = InfinispanUtil.getRemoteCache(cache);
if (remoteCache == null) {
return -1;
} else {
SessionEntityWrapper<UserSessionEntity> userSession = (SessionEntityWrapper<UserSessionEntity>) remoteCache.get(userSessionId);
SessionEntityWrapper<UserSessionEntity> userSession = remoteCache.get(userSessionId);
if (userSession == null) {
return -1;
} else {

View file

@ -151,7 +151,7 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-server-hotrod-jakarta</artifactId>
<artifactId>infinispan-server-hotrod</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>

View file

@ -1819,7 +1819,7 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>

View file

@ -104,7 +104,7 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>

View file

@ -227,7 +227,7 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core-jakarta</artifactId>
<artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>