Infinispan Protostream Marshaller (#29474)

Closes #29394

Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Pedro Ruivo 2024-06-13 17:02:46 +01:00 committed by GitHub
parent ca0833b2e4
commit 18a6c79011
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
134 changed files with 2617 additions and 4553 deletions

View file

@ -9,3 +9,12 @@ to different organizations.
When creating a social broker, you should now provide an `Alias` and optionally a `Display name` just like any other When creating a social broker, you should now provide an `Alias` and optionally a `Display name` just like any other
broker. broker.
= Infinispan marshalling changes to Infinispan Protostream
Marshalling is the process of converting Java objects into bytes to send them across the network between {project_name} servers.
With {project_name} 26, we changed the marshalling format from JBoss Marshalling to Infinispan Protostream.
WARNING: JBoss Marshalling and Infinispan Protostream are not compatible with each other and incorrect usage may lead to data loss.
Consequently, all caches are cleared when upgrading to this version.
Infinispan Protostream is based on https://protobuf.dev/programming-guides/proto3/[Protocol Buffers] (proto 3), which has the advantage of backwards/forwards compatibility.

View file

@ -0,0 +1,10 @@
= Infinispan marshalling changes
Marshalling is the process of converting Java objects into bytes to send them across the network between {project_name} servers.
With {project_name} 26, the marshalling library has changed from JBoss Marshalling to Infinispan Protostream.
The libraries are not compatible between each other and, it requires some steps to ensure the session data is not lost.
WARNING: JBoss Marshalling and Infinispan Protostream are not compatible with each other and incorrect usage may lead to data loss.
Consequently, all caches are cleared when upgrading to this version.
To prevent losing user sessions upgrade to Keycloak 25 first and enable the persistent sessions feature as outlined in the migration guide for {project_name} 25.

View file

@ -1,6 +1,10 @@
[[migration-changes]] [[migration-changes]]
== Migration Changes == Migration Changes
=== Migrating to 26.0.0
include::changes-26_0_0.adoc[leveloffset=3]
=== Migrating to 25.0.0 === Migrating to 25.0.0
include::changes-25_0_0.adoc[leveloffset=3] include::changes-25_0_0.adoc[leveloffset=3]

View file

@ -67,7 +67,23 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.infinispan</groupId> <groupId>org.infinispan</groupId>
<artifactId>infinispan-jboss-marshalling</artifactId> <artifactId>infinispan-component-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.infinispan.protostream</groupId>
<artifactId>protostream</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan.protostream</groupId>
<artifactId>protostream-types</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan.protostream</groupId>
<artifactId>protostream-processor</artifactId>
<!-- compile-only dependency -->
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -17,7 +17,6 @@
package org.keycloak.cluster.infinispan; package org.keycloak.cluster.infinispan;
import java.io.Serializable;
import java.util.Set; import java.util.Set;
import org.infinispan.Cache; import org.infinispan.Cache;
@ -35,10 +34,10 @@ abstract class CrossDCAwareCacheFactory {
protected static final Logger logger = Logger.getLogger(CrossDCAwareCacheFactory.class); protected static final Logger logger = Logger.getLogger(CrossDCAwareCacheFactory.class);
abstract BasicCache<String, Serializable> getCache(); abstract BasicCache<String, Object> getCache();
static CrossDCAwareCacheFactory getFactory(Cache<String, Serializable> workCache, Set<RemoteStore> remoteStores) { static CrossDCAwareCacheFactory getFactory(Cache<String, Object> workCache, Set<RemoteStore> remoteStores) {
if (remoteStores.isEmpty()) { if (remoteStores.isEmpty()) {
logger.debugf("No configured remoteStore available. Cross-DC scenario is not used"); logger.debugf("No configured remoteStore available. Cross-DC scenario is not used");
return new InfinispanCacheWrapperFactory(workCache); return new InfinispanCacheWrapperFactory(workCache);
@ -66,14 +65,14 @@ abstract class CrossDCAwareCacheFactory {
// We don't have external JDG configured. No cross-DC. // We don't have external JDG configured. No cross-DC.
private static class InfinispanCacheWrapperFactory extends CrossDCAwareCacheFactory { private static class InfinispanCacheWrapperFactory extends CrossDCAwareCacheFactory {
private final Cache<String, Serializable> workCache; private final Cache<String, Object> workCache;
InfinispanCacheWrapperFactory(Cache<String, Serializable> workCache) { InfinispanCacheWrapperFactory(Cache<String, Object> workCache) {
this.workCache = workCache; this.workCache = workCache;
} }
@Override @Override
BasicCache<String, Serializable> getCache() { BasicCache<String, Object> getCache() {
return workCache; return workCache;
} }
@ -83,14 +82,14 @@ abstract class CrossDCAwareCacheFactory {
// We have external JDG configured. Cross-DC should be enabled // We have external JDG configured. Cross-DC should be enabled
private static class RemoteCacheWrapperFactory extends CrossDCAwareCacheFactory { private static class RemoteCacheWrapperFactory extends CrossDCAwareCacheFactory {
private final RemoteCache<String, Serializable> remoteCache; private final RemoteCache<String, Object> remoteCache;
RemoteCacheWrapperFactory(RemoteCache<String, Serializable> remoteCache) { RemoteCacheWrapperFactory(RemoteCache<String, Object> remoteCache) {
this.remoteCache = remoteCache; this.remoteCache = remoteCache;
} }
@Override @Override
BasicCache<String, Serializable> getCache() { BasicCache<String, Object> getCache() {
// Flags are per-invocation! // Flags are per-invocation!
return remoteCache.withFlags(Flag.FORCE_RETURN_VALUE); return remoteCache.withFlags(Flag.FORCE_RETURN_VALUE);
} }

View file

@ -17,18 +17,17 @@
package org.keycloak.cluster.infinispan; package org.keycloak.cluster.infinispan;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterEvent; import org.keycloak.cluster.ClusterEvent;
import org.keycloak.cluster.ClusterListener; import org.keycloak.cluster.ClusterListener;
import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProvider;
import org.keycloak.cluster.ExecutionResult; import org.keycloak.cluster.ExecutionResult;
import org.keycloak.common.util.Retry; import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/** /**
* *
@ -130,26 +129,18 @@ public class InfinispanClusterProvider implements ClusterProvider {
this.notificationsManager.notify(taskKey, event, ignoreSender, dcNotify); this.notificationsManager.notify(taskKey, event, ignoreSender, dcNotify);
} }
private LockEntry createLockEntry() {
LockEntry lock = new LockEntry();
lock.setNode(myAddress);
lock.setTimestamp(Time.currentTime());
return lock;
}
private boolean tryLock(String cacheKey, int taskTimeoutInSeconds) { private boolean tryLock(String cacheKey, int taskTimeoutInSeconds) {
LockEntry myLock = createLockEntry(); LockEntry myLock = new LockEntry(myAddress);
LockEntry existingLock = InfinispanClusterProviderFactory.putIfAbsentWithRetries(crossDCAwareCacheFactory, cacheKey, myLock, taskTimeoutInSeconds); LockEntry existingLock = InfinispanClusterProviderFactory.putIfAbsentWithRetries(crossDCAwareCacheFactory, cacheKey, myLock, taskTimeoutInSeconds);
if (existingLock != null) { if (existingLock != null) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.tracef("Task %s in progress already by node %s. Ignoring task.", cacheKey, existingLock.getNode()); logger.tracef("Task %s in progress already by node %s. Ignoring task.", cacheKey, existingLock.node());
} }
return false; return false;
} else { } else {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.tracef("Successfully acquired lock for task %s. Our node is %s", cacheKey, myLock.getNode()); logger.tracef("Successfully acquired lock for task %s. Our node is %s", cacheKey, myLock.node());
} }
return true; return true;
} }

View file

@ -38,7 +38,6 @@ import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -59,7 +58,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
protected static final Logger logger = Logger.getLogger(InfinispanClusterProviderFactory.class); protected static final Logger logger = Logger.getLogger(InfinispanClusterProviderFactory.class);
// Infinispan cache // Infinispan cache
private volatile Cache<String, Serializable> workCache; private volatile Cache<String, Object> workCache;
// Ensure that atomic operations (like putIfAbsent) must work correctly in any of: non-clustered, clustered or cross-Data-Center (cross-DC) setups // Ensure that atomic operations (like putIfAbsent) must work correctly in any of: non-clustered, clustered or cross-Data-Center (cross-DC) setups
private CrossDCAwareCacheFactory crossDCAwareCacheFactory; private CrossDCAwareCacheFactory crossDCAwareCacheFactory;
@ -134,7 +133,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
// Will retry few times for the case when backup site not available in cross-dc environment. // Will retry few times for the case when backup site not available in cross-dc environment.
// The site might be taken offline automatically if "take-offline" properly configured // The site might be taken offline automatically if "take-offline" properly configured
static <V extends Serializable> V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) { static <V> V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) {
AtomicReference<V> resultRef = new AtomicReference<>(); AtomicReference<V> resultRef = new AtomicReference<>();
Retry.executeWithBackoff(iteration -> { Retry.executeWithBackoff(iteration -> {

View file

@ -75,7 +75,7 @@ public class InfinispanNotificationsManager {
private final ConcurrentMap<String, TaskCallback> taskCallbacks = new ConcurrentHashMap<>(); private final ConcurrentMap<String, TaskCallback> taskCallbacks = new ConcurrentHashMap<>();
private final Cache<String, Serializable> workCache; private final Cache<String, Object> workCache;
private final RemoteCache<Object, Serializable> workRemoteCache; private final RemoteCache<Object, Serializable> workRemoteCache;
@ -85,7 +85,7 @@ public class InfinispanNotificationsManager {
private final ExecutorService listenersExecutor; private final ExecutorService listenersExecutor;
protected InfinispanNotificationsManager(Cache<String, Serializable> workCache, RemoteCache<Object, Serializable> workRemoteCache, String myAddress, String mySite, ExecutorService listenersExecutor) { protected InfinispanNotificationsManager(Cache<String, Object> workCache, RemoteCache<Object, Serializable> workRemoteCache, String myAddress, String mySite, ExecutorService listenersExecutor) {
this.workCache = workCache; this.workCache = workCache;
this.workRemoteCache = workRemoteCache; this.workRemoteCache = workRemoteCache;
this.myAddress = myAddress; this.myAddress = myAddress;
@ -95,7 +95,7 @@ public class InfinispanNotificationsManager {
// Create and init manager including all listeners etc // Create and init manager including all listeners etc
public static InfinispanNotificationsManager create(KeycloakSession session, Cache<String, Serializable> workCache, String myAddress, String mySite, Set<RemoteStore> remoteStores) { public static InfinispanNotificationsManager create(KeycloakSession session, Cache<String, Object> workCache, String myAddress, String mySite, Set<RemoteStore> remoteStores) {
RemoteCache<Object, Serializable> workRemoteCache = null; RemoteCache<Object, Serializable> workRemoteCache = null;
if (!remoteStores.isEmpty()) { if (!remoteStores.isEmpty()) {
@ -141,13 +141,7 @@ public class InfinispanNotificationsManager {
void notify(String taskKey, ClusterEvent event, boolean ignoreSender, ClusterProvider.DCNotify dcNotify) { void notify(String taskKey, ClusterEvent event, boolean ignoreSender, ClusterProvider.DCNotify dcNotify) {
WrapperClusterEvent wrappedEvent = new WrapperClusterEvent(); var wrappedEvent = WrapperClusterEvent.wrap(taskKey, event, myAddress, mySite, dcNotify, ignoreSender);
wrappedEvent.setEventKey(taskKey);
wrappedEvent.setDelegateEvent(event);
wrappedEvent.setIgnoreSender(ignoreSender);
wrappedEvent.setIgnoreSenderSite(dcNotify == ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC);
wrappedEvent.setSender(myAddress);
wrappedEvent.setSenderSite(mySite);
String eventKey = UUID.randomUUID().toString(); String eventKey = UUID.randomUUID().toString();
@ -186,17 +180,17 @@ public class InfinispanNotificationsManager {
public class CacheEntryListener { public class CacheEntryListener {
@CacheEntryCreated @CacheEntryCreated
public void cacheEntryCreated(CacheEntryCreatedEvent<String, Serializable> event) { public void cacheEntryCreated(CacheEntryCreatedEvent<String, Object> event) {
eventReceived(event.getKey(), event.getValue()); eventReceived(event.getKey(), event.getValue());
} }
@CacheEntryModified @CacheEntryModified
public void cacheEntryModified(CacheEntryModifiedEvent<String, Serializable> event) { public void cacheEntryModified(CacheEntryModifiedEvent<String, Object> event) {
eventReceived(event.getKey(), event.getNewValue()); eventReceived(event.getKey(), event.getNewValue());
} }
@CacheEntryRemoved @CacheEntryRemoved
public void cacheEntryRemoved(CacheEntryRemovedEvent<String, Serializable> event) { public void cacheEntryRemoved(CacheEntryRemovedEvent<String, Object> event) {
taskFinished(event.getKey()); taskFinished(event.getKey());
} }
@ -267,7 +261,7 @@ public class InfinispanNotificationsManager {
} }
} }
private void eventReceived(String key, Serializable obj) { private void eventReceived(String key, Object obj) {
if (!(obj instanceof WrapperClusterEvent event)) { if (!(obj instanceof WrapperClusterEvent event)) {
// Items with the TASK_KEY_PREFIX might be gone fast once the locking is complete, therefore, don't log them. // Items with the TASK_KEY_PREFIX might be gone fast once the locking is complete, therefore, don't log them.
// It is still good to have the warning in case of real events return null because they have been, for example, expired // It is still good to have the warning in case of real events return null because they have been, for example, expired
@ -277,16 +271,8 @@ public class InfinispanNotificationsManager {
return; return;
} }
if (event.isIgnoreSender()) { if (event.rejectEvent(myAddress, mySite)) {
if (this.myAddress.equals(event.getSender())) { return;
return;
}
}
if (event.isIgnoreSenderSite()) {
if (this.mySite == null || this.mySite.equals(event.getSenderSite())) {
return;
}
} }
String eventKey = event.getEventKey(); String eventKey = event.getEventKey();

View file

@ -17,67 +17,14 @@
package org.keycloak.cluster.infinispan; package org.keycloak.cluster.infinispan;
import java.io.IOException; import org.infinispan.protostream.annotations.Proto;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectOutput; import org.keycloak.marshalling.Marshalling;
import java.io.Serializable;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(LockEntry.ExternalizerImpl.class) @ProtoTypeId(Marshalling.LOCK_ENTRY)
public class LockEntry implements Serializable { @Proto
public record LockEntry(String node) {
private String node;
private int timestamp;
public String getNode() {
return node;
}
public void setNode(String node) {
this.node = node;
}
public int getTimestamp() {
return timestamp;
}
public void setTimestamp(int timestamp) {
this.timestamp = timestamp;
}
public static class ExternalizerImpl implements Externalizer<LockEntry> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LockEntry obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.node, output);
KeycloakMarshallUtil.marshall(obj.timestamp, output);
}
@Override
public LockEntry readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LockEntry readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
LockEntry entry = new LockEntry();
entry.setNode(MarshallUtil.unmarshallString(input));
entry.setTimestamp(KeycloakMarshallUtil.unmarshallInteger(input));
return entry;
}
}
} }

View file

@ -18,67 +18,38 @@
package org.keycloak.cluster.infinispan; package org.keycloak.cluster.infinispan;
import org.infinispan.commons.marshall.Externalizer; import java.util.HashSet;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(LockEntryPredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.LOCK_ENTRY_PREDICATE)
public class LockEntryPredicate implements Predicate<Map.Entry<String, Serializable>> { public class LockEntryPredicate implements Predicate<Map.Entry<String, Object>> {
private final Set<String> removedNodesAddresses; private final Set<String> removedNodesAddresses;
@ProtoFactory
public LockEntryPredicate(Set<String> removedNodesAddresses) { public LockEntryPredicate(Set<String> removedNodesAddresses) {
this.removedNodesAddresses = removedNodesAddresses; this.removedNodesAddresses = removedNodesAddresses;
} }
@ProtoField(value = 1, collectionImplementation = HashSet.class)
Set<String> getRemovedNodesAddresses() {
return removedNodesAddresses;
}
@Override @Override
public boolean test(Map.Entry<String, Serializable> entry) { public boolean test(Map.Entry<String, Object> entry) {
if (!(entry.getValue() instanceof LockEntry)) { return entry.getValue() instanceof LockEntry lock &&
return false; removedNodesAddresses.contains(lock.node());
}
LockEntry lock = (LockEntry) entry.getValue();
return removedNodesAddresses.contains(lock.getNode());
} }
public static class ExternalizerImpl implements Externalizer<LockEntryPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LockEntryPredicate obj) throws IOException {
output.writeByte(VERSION_1);
KeycloakMarshallUtil.writeCollection(obj.removedNodesAddresses, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public LockEntryPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LockEntryPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return new LockEntryPredicate(
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet)
);
}
}
} }

View file

@ -17,134 +17,124 @@
package org.keycloak.cluster.infinispan; package org.keycloak.cluster.infinispan;
import org.keycloak.cluster.ClusterEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects; import java.util.Objects;
import org.infinispan.commons.marshall.Externalizer; import org.infinispan.protostream.WrappedMessage;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.Proto;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.marshalling.Marshalling;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(WrapperClusterEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.WRAPPED_CLUSTER_EVENT)
public class WrapperClusterEvent implements ClusterEvent { public class WrapperClusterEvent implements ClusterEvent {
private String eventKey; @ProtoField(1)
private String sender; final String eventKey;
private String senderSite; @ProtoField(2)
private boolean ignoreSender; final String senderAddress; // null means invoke everywhere
private boolean ignoreSenderSite; @ProtoField(3)
private ClusterEvent delegateEvent; final String senderSite; // can be null
@ProtoField(4)
final SiteFilter siteFilter;
final ClusterEvent delegateEvent;
private WrapperClusterEvent(String eventKey, String senderAddress, String senderSite, SiteFilter siteFilter, ClusterEvent delegateEvent) {
this.eventKey = Objects.requireNonNull(eventKey);
this.senderAddress = senderAddress;
this.senderSite = senderSite;
this.siteFilter = Objects.requireNonNull(siteFilter);
this.delegateEvent = Objects.requireNonNull(delegateEvent);
}
@ProtoFactory
static WrapperClusterEvent protoFactory(String eventKey, String senderAddress, String senderSite, SiteFilter siteFilter, WrappedMessage eventPS) {
return new WrapperClusterEvent(eventKey, Marshalling.emptyStringToNull(senderAddress), Marshalling.emptyStringToNull(senderSite), siteFilter, (ClusterEvent) eventPS.getValue());
}
public static WrapperClusterEvent wrap(String eventKey, ClusterEvent event, String senderAddress, String senderSite, ClusterProvider.DCNotify dcNotify, boolean ignoreSender) {
senderAddress = ignoreSender ? Objects.requireNonNull(senderAddress) : null;
senderSite = dcNotify == ClusterProvider.DCNotify.ALL_DCS ? null : senderSite;
var siteNotification = switch (dcNotify) {
case ALL_DCS -> SiteFilter.ALL;
case LOCAL_DC_ONLY -> SiteFilter.LOCAL;
case ALL_BUT_LOCAL_DC -> SiteFilter.REMOTE;
};
return new WrapperClusterEvent(eventKey, senderAddress, senderSite, siteNotification, event);
}
@ProtoField(5)
WrappedMessage getEventPS() {
return new WrappedMessage(delegateEvent);
}
public String getEventKey() { public String getEventKey() {
return eventKey; return eventKey;
} }
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getSenderSite() {
return senderSite;
}
public void setSenderSite(String senderSite) {
this.senderSite = senderSite;
}
public boolean isIgnoreSender() {
return ignoreSender;
}
public void setIgnoreSender(boolean ignoreSender) {
this.ignoreSender = ignoreSender;
}
public boolean isIgnoreSenderSite() {
return ignoreSenderSite;
}
public void setIgnoreSenderSite(boolean ignoreSenderSite) {
this.ignoreSenderSite = ignoreSenderSite;
}
public ClusterEvent getDelegateEvent() { public ClusterEvent getDelegateEvent() {
return delegateEvent; return delegateEvent;
} }
public void setDelegateEvent(ClusterEvent delegateEvent) { public boolean rejectEvent(String mySiteAddress, String mySiteName) {
this.delegateEvent = delegateEvent; return (senderAddress != null && senderAddress.equals(mySiteAddress)) ||
(senderSite != null && siteFilter.reject(senderSite, mySiteName));
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
WrapperClusterEvent that = (WrapperClusterEvent) o; WrapperClusterEvent that = (WrapperClusterEvent) o;
return ignoreSender == that.ignoreSender && ignoreSenderSite == that.ignoreSenderSite && Objects.equals(eventKey, that.eventKey) && Objects.equals(sender, that.sender) && Objects.equals(senderSite, that.senderSite) && Objects.equals(delegateEvent, that.delegateEvent); return eventKey.equals(that.eventKey) &&
Objects.equals(senderAddress, that.senderAddress) &&
Objects.equals(senderSite, that.senderSite) &&
siteFilter == that.siteFilter &&
delegateEvent.equals(that.delegateEvent);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(eventKey, sender, senderSite, ignoreSender, ignoreSenderSite, delegateEvent); int result = eventKey.hashCode();
result = 31 * result + Objects.hashCode(senderAddress);
result = 31 * result + Objects.hashCode(senderSite);
result = 31 * result + siteFilter.hashCode();
result = 31 * result + delegateEvent.hashCode();
return result;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("WrapperClusterEvent [ eventKey=%s, sender=%s, senderSite=%s, delegateEvent=%s ]", eventKey, sender, senderSite, delegateEvent.toString()); return String.format("WrapperClusterEvent [ eventKey=%s, sender=%s, senderSite=%s, delegateEvent=%s ]", eventKey, senderAddress, senderSite, delegateEvent);
} }
public static class ExternalizerImpl implements Externalizer<WrapperClusterEvent> { @Proto
@ProtoTypeId(Marshalling.WRAPPED_CLUSTER_EVENT_SITE_FILTER)
private static final int VERSION_1 = 1; public enum SiteFilter {
ALL {
@Override @Override
public void writeObject(ObjectOutput output, WrapperClusterEvent obj) throws IOException { boolean reject(String senderSite, String mySite) {
output.writeByte(VERSION_1); return false;
MarshallUtil.marshallString(obj.eventKey, output);
MarshallUtil.marshallString(obj.sender, output);
MarshallUtil.marshallString(obj.senderSite, output);
output.writeBoolean(obj.ignoreSender);
output.writeBoolean(obj.ignoreSenderSite);
output.writeObject(obj.delegateEvent);
}
@Override
public WrapperClusterEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
} }
} }, LOCAL {
@Override
boolean reject(String senderSite, String mySite) {
return !Objects.equals(senderSite, mySite);
}
}, REMOTE {
@Override
boolean reject(String senderSite, String mySite) {
return Objects.equals(senderSite, mySite);
}
};
public WrapperClusterEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException { abstract boolean reject(String senderSite, String mySite);
WrapperClusterEvent res = new WrapperClusterEvent();
res.eventKey = MarshallUtil.unmarshallString(input);
res.sender = MarshallUtil.unmarshallString(input);
res.senderSite = MarshallUtil.unmarshallString(input);
res.ignoreSender = input.readBoolean();
res.ignoreSenderSite = input.readBoolean();
res.delegateEvent = (ClusterEvent) input.readObject();
return res;
}
} }
} }

View file

@ -17,9 +17,14 @@
package org.keycloak.connections.infinispan; package org.keycloak.connections.infinispan;
import java.util.concurrent.CompletionStage;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.commons.util.concurrent.CompletionStages;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -36,6 +41,14 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection
this.topologyInfo = topologyInfo; this.topologyInfo = topologyInfo;
} }
private static PersistenceManager persistenceManager(Cache<?, ?> cache) {
return ComponentRegistry.componentOf(cache, PersistenceManager.class);
}
private static CompletionStage<Void> clearPersistenceManager(PersistenceManager persistenceManager) {
return persistenceManager.clearAllStores(PersistenceManager.AccessMode.BOTH);
}
@Override @Override
public <K, V> Cache<K, V> getCache(String name, boolean createIfAbsent) { public <K, V> Cache<K, V> getCache(String name, boolean createIfAbsent) {
return cacheManager.getCache(name, createIfAbsent); return cacheManager.getCache(name, createIfAbsent);
@ -51,6 +64,19 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection
return topologyInfo; return topologyInfo;
} }
@Override
public CompletionStage<Void> migrateToProtostream() {
// Only the CacheStore (persistence) stores data in binary format and needs to be deleted.
// We assume rolling-upgrade between KC 25 and KC 26 is not available, in other words, KC 25 and KC 26 servers are not present in the same cluster.
var stage = CompletionStages.aggregateCompletionStage();
DISTRIBUTED_REPLICATED_CACHE_NAMES.stream()
.map(this::getCache)
.map(DefaultInfinispanConnectionProvider::persistenceManager)
.map(DefaultInfinispanConnectionProvider::clearPersistenceManager)
.forEach(stage::dependsOn);
return stage.freeze();
}
@Override @Override
public void close() { public void close() {
} }

View file

@ -180,11 +180,11 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
if (providers.hasNext()) { if (providers.hasNext()) {
ManagedCacheManagerProvider provider = providers.next(); ManagedCacheManagerProvider provider = providers.next();
if (providers.hasNext()) { if (providers.hasNext()) {
throw new RuntimeException("Multiple " + org.keycloak.cluster.ManagedCacheManagerProvider.class + " providers found."); throw new RuntimeException("Multiple " + org.keycloak.cluster.ManagedCacheManagerProvider.class + " providers found.");
} }
managedCacheManager = provider.getEmbeddedCacheManager(config); managedCacheManager = provider.getEmbeddedCacheManager(config);
} }
@ -238,7 +238,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
if (clustered) { if (clustered) {
String jgroupsUdpMcastAddr = config.get("jgroupsUdpMcastAddr", System.getProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR)); String jgroupsUdpMcastAddr = config.get("jgroupsUdpMcastAddr", System.getProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR));
configureTransport(gcb, topologyInfo.getMyNodeName(), topologyInfo.getMySiteName(), jgroupsUdpMcastAddr, String jgroupsBindAddr = config.get("jgroupsBindAddr", System.getProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR));
configureTransport(gcb, topologyInfo.getMyNodeName(), topologyInfo.getMySiteName(), jgroupsUdpMcastAddr, jgroupsBindAddr,
"default-configs/default-keycloak-jgroups-udp.xml"); "default-configs/default-keycloak-jgroups-udp.xml");
gcb.jmx() gcb.jmx()
.domain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + topologyInfo.getMyNodeName()).enable(); .domain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + topologyInfo.getMyNodeName()).enable();

View file

@ -18,6 +18,8 @@
package org.keycloak.connections.infinispan; package org.keycloak.connections.infinispan;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletionStage;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
@ -57,7 +59,8 @@ public interface InfinispanConnectionProvider extends Provider {
// System property used on Wildfly to identify distributedCache address and sticky session route // System property used on Wildfly to identify distributedCache address and sticky session route
String JBOSS_NODE_NAME = "jboss.node.name"; String JBOSS_NODE_NAME = "jboss.node.name";
String JGROUPS_UDP_MCAST_ADDR = "jgroups.udp.mcast_addr"; String JGROUPS_UDP_MCAST_ADDR = "jgroups.mcast_addr";
String JGROUPS_BIND_ADDR = "jgroups.bind.address";
// TODO This property is not in Wildfly. Check if corresponding property in Wildfly exists // TODO This property is not in Wildfly. Check if corresponding property in Wildfly exists
String JBOSS_SITE_NAME = "jboss.site.name"; String JBOSS_SITE_NAME = "jboss.site.name";
@ -127,4 +130,11 @@ public interface InfinispanConnectionProvider extends Provider {
*/ */
TopologyInfo getTopologyInfo(); TopologyInfo getTopologyInfo();
/**
* Migrates the JBoss Marshalling encoding to Infinispan Protostream
*
* @return A {@link CompletionStage} to signal when the operator is completed.
*/
CompletionStage<Void> migrateToProtostream();
} }

View file

@ -102,7 +102,7 @@ public class InfinispanUtil {
private static final Object CHANNEL_INIT_SYNCHRONIZER = new Object(); private static final Object CHANNEL_INIT_SYNCHRONIZER = new Object();
public static void configureTransport(GlobalConfigurationBuilder gcb, String nodeName, String siteName, String jgroupsUdpMcastAddr, public static void configureTransport(GlobalConfigurationBuilder gcb, String nodeName, String siteName, String jgroupsUdpMcastAddr,
String jgroupsConfigPath) { String jgroupsBindAddr, String jgroupsConfigPath) {
if (nodeName == null) { if (nodeName == null) {
gcb.transport().defaultTransport(); gcb.transport().defaultTransport();
} else { } else {
@ -115,6 +115,12 @@ public class InfinispanUtil {
} else { } else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR, jgroupsUdpMcastAddr); System.setProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR, jgroupsUdpMcastAddr);
} }
var originalBindAddr = System.getProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR);
if (jgroupsBindAddr == null) {
System.getProperties().remove(InfinispanConnectionProvider.JGROUPS_BIND_ADDR);
} else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR, jgroupsBindAddr);
}
try { try {
JChannel channel = new JChannel(fileLookup.lookupFileLocation(jgroupsConfigPath, InfinispanUtil.class.getClassLoader()).openStream()); JChannel channel = new JChannel(fileLookup.lookupFileLocation(jgroupsConfigPath, InfinispanUtil.class.getClassLoader()).openStream());
channel.setName(nodeName); channel.setName(nodeName);
@ -144,6 +150,11 @@ public class InfinispanUtil {
} else { } else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR, originalMcastAddr); System.setProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR, originalMcastAddr);
} }
if (originalBindAddr == null) {
System.getProperties().remove(InfinispanConnectionProvider.JGROUPS_BIND_ADDR);
} else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR, originalBindAddr);
}
} }
} }
} }

View file

@ -17,69 +17,33 @@
package org.keycloak.keys.infinispan; package org.keycloak.keys.infinispan;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent; import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(PublicKeyStorageInvalidationEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.PUBLIC_KEY_INVALIDATION_EVENT)
public class PublicKeyStorageInvalidationEvent extends InvalidationEvent { public class PublicKeyStorageInvalidationEvent extends InvalidationEvent {
private String cacheKey; private PublicKeyStorageInvalidationEvent(String cacheKey) {
super(cacheKey);
public static PublicKeyStorageInvalidationEvent create(String cacheKey) {
PublicKeyStorageInvalidationEvent event = new PublicKeyStorageInvalidationEvent();
event.cacheKey = cacheKey;
return event;
} }
@Override @ProtoFactory
public String getId() { public static PublicKeyStorageInvalidationEvent create(String id) {
return cacheKey; return new PublicKeyStorageInvalidationEvent(id);
} }
public String getCacheKey() { public String getCacheKey() {
return cacheKey; return getId();
} }
@Override @Override
public String toString() { public String toString() {
return "PublicKeyStorageInvalidationEvent [ " + cacheKey + " ]"; return "PublicKeyStorageInvalidationEvent [ " + getId() + " ]";
}
public static class ExternalizerImpl implements Externalizer<PublicKeyStorageInvalidationEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, PublicKeyStorageInvalidationEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.cacheKey, output);
}
@Override
public PublicKeyStorageInvalidationEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public PublicKeyStorageInvalidationEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
PublicKeyStorageInvalidationEvent res = new PublicKeyStorageInvalidationEvent();
res.cacheKey = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,13 +17,12 @@
package org.keycloak.keys.infinispan; package org.keycloak.keys.infinispan;
import java.io.Serializable;
import org.keycloak.crypto.PublicKeysWrapper; import org.keycloak.crypto.PublicKeysWrapper;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class PublicKeysEntry implements Serializable { public class PublicKeysEntry {
private final int lastRequestTime; private final int lastRequestTime;

View file

@ -0,0 +1,200 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.marshalling;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.ProtoSchema;
import org.infinispan.protostream.annotations.ProtoSyntax;
import org.infinispan.protostream.types.java.CommonTypes;
import org.keycloak.cluster.infinispan.LockEntry;
import org.keycloak.cluster.infinispan.LockEntryPredicate;
import org.keycloak.cluster.infinispan.WrapperClusterEvent;
import org.keycloak.component.ComponentModel;
import org.keycloak.keys.infinispan.PublicKeyStorageInvalidationEvent;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.infinispan.authorization.events.PolicyRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.PolicyUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ScopeRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ScopeUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.stream.InResourcePredicate;
import org.keycloak.models.cache.infinispan.authorization.stream.InResourceServerPredicate;
import org.keycloak.models.cache.infinispan.authorization.stream.InScopePredicate;
import org.keycloak.models.cache.infinispan.events.AuthenticationSessionAuthNoteUpdateEvent;
import org.keycloak.models.cache.infinispan.events.ClientAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.GroupAddedEvent;
import org.keycloak.models.cache.infinispan.events.GroupMovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupRemovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.RealmRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RealmUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.RoleAddedEvent;
import org.keycloak.models.cache.infinispan.events.RoleRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RoleUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.UserCacheRealmInvalidationEvent;
import org.keycloak.models.cache.infinispan.events.UserConsentsUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.UserFederationLinkRemovedEvent;
import org.keycloak.models.cache.infinispan.events.UserFederationLinkUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.UserFullInvalidationEvent;
import org.keycloak.models.cache.infinispan.events.UserUpdatedEvent;
import org.keycloak.models.cache.infinispan.stream.GroupListPredicate;
import org.keycloak.models.cache.infinispan.stream.HasRolePredicate;
import org.keycloak.models.cache.infinispan.stream.InClientPredicate;
import org.keycloak.models.cache.infinispan.stream.InGroupPredicate;
import org.keycloak.models.cache.infinispan.stream.InIdentityProviderPredicate;
import org.keycloak.models.cache.infinispan.stream.InRealmPredicate;
import org.keycloak.models.sessions.infinispan.changes.ReplaceFunction;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.sessions.LastSessionRefreshEvent;
import org.keycloak.models.sessions.infinispan.changes.sessions.SessionData;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore;
import org.keycloak.models.sessions.infinispan.entities.AuthenticationSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SingleUseObjectValueEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailuresEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.initializer.InitializerState;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.sessions.CommonClientSessionModel;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.managers.UserStorageSyncManager;
@ProtoSchema(
syntax = ProtoSyntax.PROTO3,
schemaPackageName = "keycloak",
schemaFilePath = "proto/generated",
// common-types for UUID
dependsOn = CommonTypes.class,
includeClasses = {
// Model
UserSessionModel.State.class,
CommonClientSessionModel.ExecutionStatus.class,
ComponentModel.MultiMapEntry.class,
UserStorageProviderModel.class,
UserStorageSyncManager.UserStorageProviderClusterEvent.class,
// clustering.infinispan package
LockEntry.class,
LockEntryPredicate.class,
WrapperClusterEvent.class,
WrapperClusterEvent.SiteFilter.class,
// keys.infinispan package
PublicKeyStorageInvalidationEvent.class,
//models.cache.infinispan.authorization.events package
PolicyUpdatedEvent.class,
PolicyRemovedEvent.class,
ResourceUpdatedEvent.class,
ResourceRemovedEvent.class,
ResourceServerUpdatedEvent.class,
ResourceServerRemovedEvent.class,
ScopeUpdatedEvent.class,
ScopeRemovedEvent.class,
// models.sessions.infinispan.initializer package
InitializerState.class,
// models.sessions.infinispan.changes package
SessionEntityWrapper.class,
// models.sessions.infinispan.changes.sessions package
LastSessionRefreshEvent.class,
SessionData.class,
// models.cache.infinispan.authorization.stream package
InResourcePredicate.class,
InResourceServerPredicate.class,
InScopePredicate.class,
// models.sessions.infinispan.events package
RealmRemovedSessionEvent.class,
RemoveAllUserLoginFailuresEvent.class,
RemoveUserSessionsEvent.class,
// models.sessions.infinispan.stream package
SessionPredicate.class,
SessionWrapperPredicate.class,
UserSessionPredicate.class,
// models.cache.infinispan.stream package
GroupListPredicate.class,
HasRolePredicate.class,
InClientPredicate.class,
InGroupPredicate.class,
InIdentityProviderPredicate.class,
InRealmPredicate.class,
// models.cache.infinispan.events package
AuthenticationSessionAuthNoteUpdateEvent.class,
ClientAddedEvent.class,
ClientUpdatedEvent.class,
ClientRemovedEvent.class,
ClientScopeAddedEvent.class,
ClientScopeRemovedEvent.class,
GroupAddedEvent.class,
GroupMovedEvent.class,
GroupRemovedEvent.class,
GroupUpdatedEvent.class,
RealmUpdatedEvent.class,
RealmRemovedEvent.class,
RoleAddedEvent.class,
RoleUpdatedEvent.class,
RoleRemovedEvent.class,
UserCacheRealmInvalidationEvent.class,
UserConsentsUpdatedEvent.class,
UserFederationLinkRemovedEvent.class,
UserFederationLinkUpdatedEvent.class,
UserFullInvalidationEvent.class,
UserUpdatedEvent.class,
// sessions.infinispan.entities package
AuthenticatedClientSessionStore.class,
AuthenticatedClientSessionEntity.class,
AuthenticationSessionEntity.class,
LoginFailureEntity.class,
LoginFailureKey.class,
RootAuthenticationSessionEntity.class,
SingleUseObjectValueEntity.class,
UserSessionEntity.class,
ReplaceFunction.class
}
)
public interface KeycloakModelSchema extends GeneratedSchema {
KeycloakModelSchema INSTANCE = new KeycloakModelSchemaImpl();
}

View file

@ -1,25 +1,155 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.marshalling; package org.keycloak.marshalling;
import org.infinispan.configuration.global.GlobalConfigurationBuilder; import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.jboss.marshalling.core.JBossUserMarshaller;
import org.keycloak.models.sessions.infinispan.changes.ReplaceFunction;
@SuppressWarnings("removal") /**
* Ids of the protostream type.
* <p>
* Read careful the following warning to ensure compatibility when updating schemas.
* <p>
* WARNING! IDs lower or equal than 65535 are reserved for internal Inifinispan classes and cannot be used.
* WARNING! ID defined in this class must be unique. If one type is removed, its ID must not be reused. You have been
* warned! The ID identifies the message, and it is stored and used to save space.
* WARNING! The field IDs cannot be reused as well for the same reason.
* WARNING! Primitive types cannot be null in proto3 syntax (Integer, String). Take that in consideration.
* <p>
* Be Aware of the following default in Proto3 syntax!
* For strings, the default value is the empty string.
* For bytes, the default value is empty bytes.
* For bools, the default value is false.
* For numeric types, the default value is zero.
* For enums, the default value is the first defined enum value, which must be 0.
* For message fields, the field is not set. (null)
* <p>
* Docs: <a href="https://protobuf.dev/programming-guides/proto3/">Language Guide (proto 3)</a>
*/
public final class Marshalling { public final class Marshalling {
private Marshalling() { private Marshalling() {
} }
// Note: Min ID is 2500 // Model
public static final Integer REPLACE_FUNCTION_ID = 2500; // see org.keycloak.models.UserSessionModel.State
public static final int USER_STATE_ENUM = 65536;
// see org.keycloak.sessions.CommonClientSessionModel.ExecutionStatus
public static final int CLIENT_SESSION_EXECUTION_STATUS = 65537;
// see org.keycloak.component.ComponentModel.MultiMapEntry
public static final int MULTIMAP_ENTRY = 65538;
// see org.keycloak.storage.UserStorageProviderModel
public static final int USER_STORAGE_PROVIDER_MODES = 65539;
// see org.keycloak.storage.managers.UserStorageSyncManager.UserStorageProviderClusterEvent
public static final int USER_STORAGE_PROVIDER_CLUSTER_EVENT = 65540;
// clustering.infinispan package
public static final int LOCK_ENTRY = 65541;
public static final int LOCK_ENTRY_PREDICATE = 65542;
public static final int WRAPPED_CLUSTER_EVENT = 65543;
public static final int WRAPPED_CLUSTER_EVENT_SITE_FILTER = 65544;
// keys.infinispan package
public static final int PUBLIC_KEY_INVALIDATION_EVENT = 65545;
//models.cache.infinispan.authorization.events package
public static final int POLICY_UPDATED_EVENT = 65546;
public static final int POLICY_REMOVED_EVENT = 65547;
public static final int RESOURCE_UPDATED_EVENT = 65548;
public static final int RESOURCE_REMOVED_EVENT = 65549;
public static final int RESOURCE_SERVER_UPDATED_EVENT = 65550;
public static final int RESOURCE_SERVER_REMOVED_EVENT = 65551;
public static final int SCOPE_UPDATED_EVENT = 65552;
public static final int SCOPE_REMOVED_EVENT = 65553;
// models.sessions.infinispan.initializer package
public static final int INITIALIZER_STATE = 65554;
// models.sessions.infinispan.changes package
public static final int SESSION_ENTITY_WRAPPER = 65555;
public static final int REPLACE_FUNCTION = 65656;
// models.sessions.infinispan.changes.sessions package
public static final int LAST_SESSION_REFRESH_EVENT = 65557;
public static final int SESSION_DATA = 65558;
// models.cache.infinispan.authorization.stream package
public static final int IN_RESOURCE_PREDICATE = 65559;
public static final int IN_RESOURCE_SERVER_PREDICATE = 65560;
public static final int IN_SCOPE_PREDICATE = 65561;
// models.sessions.infinispan.events package
public static final int REALM_REMOVED_SESSION_EVENT = 65562;
public static final int REMOVE_ALL_USER_LOGIN_FAILURES_EVENT = 65563;
public static final int REMOVE_ALL_USER_SESSIONS_EVENT = 65564;
// models.sessions.infinispan.stream package
public static final int SESSION_PREDICATE = 65565;
public static final int SESSION_WRAPPER_PREDICATE = 65566;
public static final int USER_SESSION_PREDICATE = 65567;
// models.cache.infinispan.stream package
public static final int GROUP_LIST_PREDICATE = 65568;
public static final int HAS_ROLE_PREDICATE = 65569;
public static final int IN_CLIENT_PREDICATE = 65570;
public static final int IN_GROUP_PREDICATE = 65571;
public static final int IN_IDENTITY_PROVIDER_PREDICATE = 65572;
public static final int IN_REALM_PREDICATE = 65573;
// models.cache.infinispan.events package
public static final int AUTHENTICATION_SESSION_AUTH_NOTE_UPDATE_EVENT = 65574;
public static final int CLIENT_ADDED_EVENT = 65575;
public static final int CLIENT_UPDATED_EVENT = 65576;
public static final int CLIENT_REMOVED_EVENT = 65577;
public static final int CLIENT_SCOPE_ADDED_EVENT = 65578;
public static final int CLIENT_SCOPE_REMOVED_EVENT = 65579;
public static final int GROUP_ADDED_EVENT = 65580;
public static final int GROUP_MOVED_EVENT = 65581;
public static final int GROUP_REMOVED_EVENT = 65582;
public static final int GROUP_UPDATED_EVENT = 65583;
public static final int REALM_UPDATED_EVENT = 65584;
public static final int REALM_REMOVED_EVENT = 65585;
public static final int ROLE_ADDED_EVENT = 65586;
public static final int ROLE_UPDATED_EVENT = 65587;
public static final int ROLE_REMOVED_EVENT = 65588;
public static final int USER_CACHE_REALM_INVALIDATION_EVENT = 65589;
public static final int USER_CONSENTS_UPDATED_EVENT = 65590;
public static final int USER_FEDERATION_LINK_REMOVED_EVENT = 65591;
public static final int USER_FEDERATION_LINK_UPDATED_EVENT = 65592;
public static final int USER_FULL_INVALIDATION_EVENT = 65593;
public static final int USER_UPDATED_EVENT = 65594;
// sessions.infinispan.entities package
public static final int AUTHENTICATED_CLIENT_SESSION_STORE = 65595;
public static final int AUTHENTICATED_CLIENT_SESSION_ENTITY = 65596;
public static final int AUTHENTICATION_SESSION_ENTITY = 65597;
public static final int LOGIN_FAILURE_ENTITY = 65598;
public static final int LOGIN_FAILURE_KEY = 65599;
public static final int ROOT_AUTHENTICATION_SESSION_ENTITY = 65600;
public static final int SINGLE_USE_OBJECT_VALUE_ENTITY = 65601;
public static final int USER_SESSION_ENTITY = 65602;
// For Infinispan 10, we go with the JBoss marshalling.
// TODO: This should be replaced later with the marshalling recommended by infinispan. Probably protostream.
// See https://infinispan.org/docs/stable/titles/developing/developing.html#marshalling for the details
public static void configure(GlobalConfigurationBuilder builder) { public static void configure(GlobalConfigurationBuilder builder) {
builder.serialization() builder.serialization()
.marshaller(new JBossUserMarshaller()) .addContextInitializer(KeycloakModelSchema.INSTANCE);
.addAdvancedExternalizer(ReplaceFunction.INSTANCE);
} }
public static String emptyStringToNull(String value) {
return value == null || value.isEmpty() ? null : value;
}
} }

View file

@ -17,27 +17,73 @@
package org.keycloak.models.cache.infinispan; package org.keycloak.models.cache.infinispan;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.client.clienttype.ClientTypeManager; import org.keycloak.client.clienttype.ClientTypeManager;
import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.*; import org.keycloak.models.ClientInitialAccessModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientProvider;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.ClientScopeProvider;
import org.keycloak.models.GroupModel;
import org.keycloak.models.GroupProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel;
import org.keycloak.models.RoleProvider;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CacheRealmProvider; import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.CachedRealmModel; import org.keycloak.models.cache.CachedRealmModel;
import org.keycloak.models.cache.infinispan.entities.*; import org.keycloak.models.cache.infinispan.entities.CachedClient;
import org.keycloak.models.cache.infinispan.events.*; import org.keycloak.models.cache.infinispan.entities.CachedClientRole;
import org.keycloak.models.cache.infinispan.entities.CachedClientScope;
import org.keycloak.models.cache.infinispan.entities.CachedGroup;
import org.keycloak.models.cache.infinispan.entities.CachedRealm;
import org.keycloak.models.cache.infinispan.entities.CachedRealmRole;
import org.keycloak.models.cache.infinispan.entities.CachedRole;
import org.keycloak.models.cache.infinispan.entities.ClientListQuery;
import org.keycloak.models.cache.infinispan.entities.ClientScopeListQuery;
import org.keycloak.models.cache.infinispan.entities.GroupListQuery;
import org.keycloak.models.cache.infinispan.entities.GroupNameQuery;
import org.keycloak.models.cache.infinispan.entities.RealmListQuery;
import org.keycloak.models.cache.infinispan.entities.RoleListQuery;
import org.keycloak.models.cache.infinispan.events.ClientAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.GroupAddedEvent;
import org.keycloak.models.cache.infinispan.events.GroupMovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupRemovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.cache.infinispan.events.RealmRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RealmUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.RoleAddedEvent;
import org.keycloak.models.cache.infinispan.events.RoleRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RoleUpdatedEvent;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.DatastoreProvider; import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.StoreManagers;
import org.keycloak.storage.StorageId; import org.keycloak.storage.StorageId;
import org.keycloak.storage.StoreManagers;
import org.keycloak.storage.client.ClientStorageProviderModel; import org.keycloak.storage.client.ClientStorageProviderModel;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* - the high level architecture of this cache is an invalidation cache. * - the high level architecture of this cache is an invalidation cache.
@ -221,7 +267,6 @@ public class RealmCacheSession implements CacheRealmProvider {
public void registerClientScopeInvalidation(String id, String realmId) { public void registerClientScopeInvalidation(String id, String realmId) {
invalidateClientScope(id); invalidateClientScope(id);
cache.clientScopeUpdated(realmId, invalidations); cache.clientScopeUpdated(realmId, invalidations);
invalidationEvents.add(ClientTemplateEvent.create(id));
} }
private void invalidateClientScope(String id) { private void invalidateClientScope(String id) {
@ -561,7 +606,7 @@ public class RealmCacheSession implements CacheRealmProvider {
// this is needed so that a client that hasn't been committed isn't cached in a query // this is needed so that a client that hasn't been committed isn't cached in a query
listInvalidations.add(realm.getId()); listInvalidations.add(realm.getId());
invalidationEvents.add(ClientAddedEvent.create(client.getId(), client.getClientId(), realm.getId())); invalidationEvents.add(ClientAddedEvent.create(client.getId(), realm.getId()));
cache.clientAdded(realm.getId(), invalidations); cache.clientAdded(realm.getId(), invalidations);
return client; return client;
} }

View file

@ -62,7 +62,7 @@ public class StoreFactoryCacheManager extends CacheManager {
public void resourceServerRemoval(String id, Set<String> invalidations) { public void resourceServerRemoval(String id, Set<String> invalidations) {
resourceServerUpdated(id, invalidations); resourceServerUpdated(id, invalidations);
addInvalidations(InResourceServerPredicate.create().resourceServer(id), invalidations); addInvalidations(InResourceServerPredicate.create(id), invalidations);
} }
public void scopeUpdated(String id, String name, String serverId, Set<String> invalidations) { public void scopeUpdated(String id, String name, String serverId, Set<String> invalidations) {
@ -74,7 +74,7 @@ public class StoreFactoryCacheManager extends CacheManager {
public void scopeRemoval(String id, String name, String serverId, Set<String> invalidations) { public void scopeRemoval(String id, String name, String serverId, Set<String> invalidations) {
scopeUpdated(id, name, serverId, invalidations); scopeUpdated(id, name, serverId, invalidations);
addInvalidations(InScopePredicate.create().scope(id), invalidations); addInvalidations(InScopePredicate.create(id), invalidations);
} }
public void resourceUpdated(String id, String name, String type, Set<String> uris, Set<String> scopes, String serverId, String owner, Set<String> invalidations) { public void resourceUpdated(String id, String name, String type, Set<String> uris, Set<String> scopes, String serverId, String owner, Set<String> invalidations) {
@ -83,14 +83,14 @@ public class StoreFactoryCacheManager extends CacheManager {
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId)); invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, null)); invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, null));
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(id, serverId)); invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(id, serverId));
addInvalidations(InResourcePredicate.create().resource(name), invalidations); addInvalidations(InResourcePredicate.create(name), invalidations);
if (type != null) { if (type != null) {
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId)); invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, owner, serverId)); invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, owner, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, null, serverId)); invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, null, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByTypeInstanceCacheKey(type, serverId)); invalidations.add(StoreFactoryCacheSession.getResourceByTypeInstanceCacheKey(type, serverId));
addInvalidations(InResourcePredicate.create().resource(type), invalidations); addInvalidations(InResourcePredicate.create(type), invalidations);
} }
if (uris != null) { if (uris != null) {
@ -102,14 +102,14 @@ public class StoreFactoryCacheManager extends CacheManager {
if (scopes != null) { if (scopes != null) {
for (String scope : scopes) { for (String scope : scopes) {
invalidations.add(StoreFactoryCacheSession.getResourceByScopeCacheKey(scope, serverId)); invalidations.add(StoreFactoryCacheSession.getResourceByScopeCacheKey(scope, serverId));
addInvalidations(InScopePredicate.create().scope(scope), invalidations); addInvalidations(InScopePredicate.create(scope), invalidations);
} }
} }
} }
public void resourceRemoval(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId, Set<String> invalidations) { public void resourceRemoval(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId, Set<String> invalidations) {
resourceUpdated(id, name, type, uris, scopes, serverId, owner, invalidations); resourceUpdated(id, name, type, uris, scopes, serverId, owner, invalidations);
addInvalidations(InResourcePredicate.create().resource(id), invalidations); addInvalidations(InResourcePredicate.create(id), invalidations);
} }
public void policyUpdated(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId, Set<String> invalidations) { public void policyUpdated(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId, Set<String> invalidations) {

View file

@ -270,7 +270,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
ResourceAdapter adapter = managedResources.get(id); ResourceAdapter adapter = managedResources.get(id);
if (adapter != null) adapter.invalidateFlag(); if (adapter != null) adapter.invalidateFlag();
invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uris, scopes, serverId, owner)); invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uris, owner, scopes, serverId));
} }
public void registerPolicyInvalidation(String id, String name, Set<String> resources, Set<String> scopes, String defaultResourceType, String serverId) { public void registerPolicyInvalidation(String id, String name, Set<String> resources, Set<String> scopes, String defaultResourceType, String serverId) {
@ -443,7 +443,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
if (server == null) return; if (server == null) return;
cache.invalidateObject(id); cache.invalidateObject(id);
invalidationEvents.add(ResourceServerRemovedEvent.create(id, server.getId())); invalidationEvents.add(ResourceServerRemovedEvent.create(id));
cache.resourceServerRemoval(id, invalidations); cache.resourceServerRemoval(id, invalidations);
getResourceServerStoreDelegate().delete(client); getResourceServerStoreDelegate().delete(client);

View file

@ -0,0 +1,78 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.authorization.events;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BasePolicyEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoField(2)
final String name;
@ProtoField(value = 3, collectionImplementation = HashSet.class)
final Set<String> resources;
@ProtoField(value = 4, collectionImplementation = HashSet.class)
final Set<String> resourceTypes;
@ProtoField(value = 5, collectionImplementation = HashSet.class)
final Set<String> scopes;
@ProtoField(6)
final String serverId;
BasePolicyEvent(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
super(id);
this.name = Objects.requireNonNull(name);
this.resources = resources;
this.resourceTypes = resourceTypes;
this.scopes = scopes;
this.serverId = Objects.requireNonNull(serverId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BasePolicyEvent that = (BasePolicyEvent) o;
return name.equals(that.name) &&
Objects.equals(resources, that.resources) &&
Objects.equals(resourceTypes, that.resourceTypes) &&
Objects.equals(scopes, that.scopes) &&
serverId.equals(that.serverId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + Objects.hashCode(resources);
result = 31 * result + Objects.hashCode(resourceTypes);
result = 31 * result + Objects.hashCode(scopes);
result = 31 * result + serverId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [id=%s, name=%s]", getClass().getSimpleName(), getId(), name);
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.authorization.events;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BaseResourceEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoField(2)
final String name;
@ProtoField(3)
final String owner;
@ProtoField(4)
final String serverId;
@ProtoField(5)
final String type;
@ProtoField(value = 6, collectionImplementation = HashSet.class)
final Set<String> uris;
@ProtoField(value = 7, collectionImplementation = HashSet.class)
final Set<String> scopes;
BaseResourceEvent(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
super(id);
this.name = Objects.requireNonNull(name);
this.owner = Objects.requireNonNull(owner);
this.serverId = Objects.requireNonNull(serverId);
this.type = type;
this.uris = uris;
this.scopes = scopes;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseResourceEvent that = (BaseResourceEvent) o;
return name.equals(that.name) &&
owner.equals(that.owner) &&
serverId.equals(that.serverId) &&
Objects.equals(type, that.type) &&
Objects.equals(uris, that.uris) &&
Objects.equals(scopes, that.scopes);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + owner.hashCode();
result = 31 * result + serverId.hashCode();
result = 31 * result + Objects.hashCode(type);
result = 31 * result + Objects.hashCode(uris);
result = 31 * result + Objects.hashCode(scopes);
return result;
}
@Override
public String toString() {
return String.format("%s [ id=%s, name=%s]", getClass().getSimpleName(), getId(), name);
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BaseResourceServerEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
BaseResourceServerEvent(String id) {
super(id);
}
@Override
public String toString() {
return String.format("%s [ id=%s ]", getClass().getSimpleName(), getId());
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.authorization.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BaseScopeEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoField(2)
final String name;
@ProtoField(3)
final String serverId;
BaseScopeEvent(String id, String name, String serverId) {
super(id);
this.name = Objects.requireNonNull(name);
this.serverId = Objects.requireNonNull(serverId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseScopeEvent that = (BaseScopeEvent) o;
return name.equals(that.name) &&
serverId.equals(that.serverId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + serverId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ id=%s, name=%s ]", getClass(), getId(), name);
}
}

View file

@ -28,7 +28,6 @@ import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
*/ */
public class PermissionTicketRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class PermissionTicketRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String owner; private String owner;
private String resource; private String resource;
private String scope; private String scope;
@ -36,9 +35,12 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
private String requester; private String requester;
private String resourceName; private String resourceName;
private PermissionTicketRemovedEvent(String id) {
super(id);
}
public static PermissionTicketRemovedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) { public static PermissionTicketRemovedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) {
PermissionTicketRemovedEvent event = new PermissionTicketRemovedEvent(); PermissionTicketRemovedEvent event = new PermissionTicketRemovedEvent(id);
event.id = id;
event.owner = owner; event.owner = owner;
event.requester = requester; event.requester = requester;
event.resource = resource; event.resource = resource;
@ -48,32 +50,27 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
return event; return event;
} }
@Override
public String getId() {
return id;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
PermissionTicketRemovedEvent that = (PermissionTicketRemovedEvent) o; PermissionTicketRemovedEvent that = (PermissionTicketRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId); return Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), id, resource, serverId); return Objects.hash(super.hashCode(), resource, serverId);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("PermissionTicketRemovedEvent [ id=%s, name=%s]", id, resource); return String.format("PermissionTicketRemovedEvent [ id=%s, name=%s]", getId(), resource);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.permissionTicketRemoval(id, owner, requester, resource, resourceName, scope, serverId, invalidations); cache.permissionTicketRemoval(getId(), owner, requester, resource, resourceName, scope, serverId, invalidations);
} }
} }

View file

@ -28,7 +28,6 @@ import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
*/ */
public class PermissionTicketUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class PermissionTicketUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String owner; private String owner;
private String resource; private String resource;
private String scope; private String scope;
@ -36,9 +35,12 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
private String requester; private String requester;
private String resourceName; private String resourceName;
private PermissionTicketUpdatedEvent(String id) {
super(id);
}
public static PermissionTicketUpdatedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) { public static PermissionTicketUpdatedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) {
PermissionTicketUpdatedEvent event = new PermissionTicketUpdatedEvent(); PermissionTicketUpdatedEvent event = new PermissionTicketUpdatedEvent(id);
event.id = id;
event.owner = owner; event.owner = owner;
event.requester = requester; event.requester = requester;
event.resource = resource; event.resource = resource;
@ -48,34 +50,27 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
return event; return event;
} }
@Override
public String getId() {
return id;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
PermissionTicketUpdatedEvent that = (PermissionTicketUpdatedEvent) o; PermissionTicketUpdatedEvent that = (PermissionTicketUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId); return Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), id, resource, serverId); return Objects.hash(super.hashCode(), resource, serverId);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("PermissionTicketUpdatedEvent [ id=%s, name=%s]", id, resource); return String.format("PermissionTicketUpdatedEvent [ id=%s, name=%s]", getId(), resource);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.permissionTicketUpdated(id, owner, requester, resource, resourceName, scope, serverId, invalidations); cache.permissionTicketUpdated(getId(), owner, requester, resource, resourceName, scope, serverId, invalidations);
} }
} }

View file

@ -17,109 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager; import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(PolicyRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.POLICY_REMOVED_EVENT)
public class PolicyRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class PolicyRemovedEvent extends BasePolicyEvent {
private String id; @ProtoFactory
private String name; PolicyRemovedEvent(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
private Set<String> resources; super(id, name, resources, resourceTypes, scopes, serverId);
private Set<String> resourceTypes; }
private Set<String> scopes;
private String serverId;
public static PolicyRemovedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) { public static PolicyRemovedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
PolicyRemovedEvent event = new PolicyRemovedEvent(); return new PolicyRemovedEvent(id, name, resources, resourceTypes, scopes, serverId);
event.id = id;
event.name = name;
event.resources = resources;
event.resourceTypes = resourceTypes;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PolicyRemovedEvent that = (PolicyRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
}
@Override
public String toString() {
return String.format("PolicyRemovedEvent [ id=%s, name=%s]", id, name);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyRemoval(id, name, resources, resourceTypes, scopes, serverId, invalidations); cache.policyRemoval(getId(), name, resources, resourceTypes, scopes, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<PolicyRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, PolicyRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.resources, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.resourceTypes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public PolicyRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public PolicyRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
PolicyRemovedEvent res = new PolicyRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.resources = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.resourceTypes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,109 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(PolicyUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.POLICY_UPDATED_EVENT)
public class PolicyUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class PolicyUpdatedEvent extends BasePolicyEvent {
private String id; @ProtoFactory
private String name; PolicyUpdatedEvent(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
private Set<String> resources; super(id, name, resources, resourceTypes, scopes, serverId);
private Set<String> resourceTypes; }
private Set<String> scopes;
private String serverId;
public static PolicyUpdatedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) { public static PolicyUpdatedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
PolicyUpdatedEvent event = new PolicyUpdatedEvent(); return new PolicyUpdatedEvent(id, name, resources, resourceTypes, scopes, serverId);
event.id = id;
event.name = name;
event.resources = resources;
event.resourceTypes = resourceTypes;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PolicyUpdatedEvent that = (PolicyUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
}
@Override
public String toString() {
return String.format("PolicyUpdatedEvent [ id=%s, name=%s ]", id, name);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations); cache.policyUpdated(getId(), name, resources, resourceTypes, scopes, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<PolicyUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, PolicyUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
KeycloakMarshallUtil.writeCollection(obj.resources, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.resourceTypes, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public PolicyUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public PolicyUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
PolicyUpdatedEvent res = new PolicyUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.resources = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.resourceTypes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,113 +17,34 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ResourceRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.RESOURCE_REMOVED_EVENT)
public class ResourceRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class ResourceRemovedEvent extends BaseResourceEvent {
private String id; @ProtoFactory
private String name; static ResourceRemovedEvent protoFactory(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
private String owner; return new ResourceRemovedEvent(id, name, owner, serverId, Marshalling.emptyStringToNull(type), uris, scopes);
private String serverId; }
private String type;
private Set<String> uris; private ResourceRemovedEvent(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
private Set<String> scopes; super(id, name, owner, serverId, type, uris, scopes);
}
public static ResourceRemovedEvent create(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId) { public static ResourceRemovedEvent create(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId) {
ResourceRemovedEvent event = new ResourceRemovedEvent(); return new ResourceRemovedEvent(id, name, owner, serverId, type, uris, scopes);
event.id = id;
event.name = name;
event.type = type;
event.uris = uris;
event.owner = owner;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ResourceRemovedEvent that = (ResourceRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(owner, that.owner) && Objects.equals(serverId, that.serverId) && Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, owner, serverId, type);
}
@Override
public String toString() {
return String.format("ResourceRemovedEvent [ id=%s, name=%s ]", id, name);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceRemoval(id, name, type, uris, owner, scopes, serverId, invalidations); cache.resourceRemoval(getId(), name, type, uris, owner, scopes, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ResourceRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.type, output);
KeycloakMarshallUtil.writeCollection(obj.uris, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.owner, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public ResourceRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceRemovedEvent res = new ResourceRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.type = MarshallUtil.unmarshallString(input);
res.uris = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.owner = MarshallUtil.unmarshallString(input);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,91 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ResourceServerRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.RESOURCE_SERVER_REMOVED_EVENT)
public class ResourceServerRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class ResourceServerRemovedEvent extends BaseResourceServerEvent {
private String id; @ProtoFactory
private String clientId; ResourceServerRemovedEvent(String id) {
super(id);
public static ResourceServerRemovedEvent create(String id, String clientId) {
ResourceServerRemovedEvent event = new ResourceServerRemovedEvent();
event.id = id;
event.clientId = clientId;
return event;
} }
@Override public static ResourceServerRemovedEvent create(String id) {
public String getId() { return new ResourceServerRemovedEvent(id);
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ResourceServerRemovedEvent that = (ResourceServerRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(clientId, that.clientId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, clientId);
}
@Override
public String toString() {
return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceServerRemoval(id, invalidations); cache.resourceServerRemoval(getId(), invalidations);
}
public static class ExternalizerImpl implements Externalizer<ResourceServerRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceServerRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.clientId, output);
}
@Override
public ResourceServerRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceServerRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceServerRemovedEvent res = new ResourceServerRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,72 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Set; import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ResourceServerUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.RESOURCE_SERVER_UPDATED_EVENT)
public class ResourceServerUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class ResourceServerUpdatedEvent extends BaseResourceServerEvent {
private String id; @ProtoFactory
ResourceServerUpdatedEvent(String id) {
super(id);
}
public static ResourceServerUpdatedEvent create(String id) { public static ResourceServerUpdatedEvent create(String id) {
ResourceServerUpdatedEvent event = new ResourceServerUpdatedEvent(); return new ResourceServerUpdatedEvent(id);
event.id = id;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, id);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceServerUpdated(id, invalidations); cache.resourceServerUpdated(getId(), invalidations);
}
public static class ExternalizerImpl implements Externalizer<ResourceServerUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceServerUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
}
@Override
public ResourceServerUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceServerUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceServerUpdatedEvent res = new ResourceServerUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,113 +17,35 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ResourceUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.RESOURCE_UPDATED_EVENT)
public class ResourceUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class ResourceUpdatedEvent extends BaseResourceEvent {
private String id; @ProtoFactory
private String name; static ResourceUpdatedEvent protoFactory(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
private String serverId; return new ResourceUpdatedEvent(id, name, owner, serverId, Marshalling.emptyStringToNull(type), uris, scopes);
private String type;
private Set<String> uris;
private Set<String> scopes;
private String owner;
public static ResourceUpdatedEvent create(String id, String name, String type, Set<String> uris, Set<String> scopes, String serverId, String owner) {
ResourceUpdatedEvent event = new ResourceUpdatedEvent();
event.id = id;
event.name = name;
event.type = type;
event.uris = uris;
event.scopes = scopes;
event.serverId = serverId;
event.owner = owner;
return event;
} }
@Override private ResourceUpdatedEvent(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
public String getId() { super(id, name, owner, serverId, type, uris, scopes);
return id;
} }
@Override public static ResourceUpdatedEvent create(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId) {
public boolean equals(Object o) { return new ResourceUpdatedEvent(id, name, owner, serverId, type, uris, scopes);
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ResourceUpdatedEvent that = (ResourceUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId) && Objects.equals(type, that.type) && Objects.equals(owner, that.owner);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId, type, owner);
}
@Override
public String toString() {
return String.format("ResourceUpdatedEvent [ id=%s, name=%s ]", id, name);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceUpdated(id, name, type, uris, scopes, serverId, owner, invalidations); cache.resourceUpdated(getId(), name, type, uris, scopes, serverId, owner, invalidations);
} }
public static class ExternalizerImpl implements Externalizer<ResourceUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.type, output);
KeycloakMarshallUtil.writeCollection(obj.uris, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
MarshallUtil.marshallString(obj.owner, output);
}
@Override
public ResourceUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceUpdatedEvent res = new ResourceUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.type = MarshallUtil.unmarshallString(input);
res.uris = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
res.owner = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -17,95 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ScopeRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.SCOPE_REMOVED_EVENT)
public class ScopeRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class ScopeRemovedEvent extends BaseScopeEvent {
private String id; @ProtoFactory
private String name; ScopeRemovedEvent(String id, String name, String serverId) {
private String serverId; super(id, name, serverId);
}
public static ScopeRemovedEvent create(String id, String name, String serverId) { public static ScopeRemovedEvent create(String id, String name, String serverId) {
ScopeRemovedEvent event = new ScopeRemovedEvent(); return new ScopeRemovedEvent(id, name, serverId);
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ScopeRemovedEvent [ id=%s, name=%s]", id, name);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ScopeRemovedEvent that = (ScopeRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.scopeRemoval(id, name, serverId, invalidations); cache.scopeRemoval(getId(), name, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ScopeRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ScopeRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public ScopeRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ScopeRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ScopeRemovedEvent res = new ScopeRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,95 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events; package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ScopeUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.SCOPE_UPDATED_EVENT)
public class ScopeUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent { public class ScopeUpdatedEvent extends BaseScopeEvent {
private String id; @ProtoFactory
private String name; ScopeUpdatedEvent(String id, String name, String serverId) {
private String serverId; super(id, name, serverId);
}
public static ScopeUpdatedEvent create(String id, String name, String serverId) { public static ScopeUpdatedEvent create(String id, String name, String serverId) {
ScopeUpdatedEvent event = new ScopeUpdatedEvent(); return new ScopeUpdatedEvent(id, name, serverId);
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ScopeUpdatedEvent that = (ScopeUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
}
@Override
public String toString() {
return String.format("ScopeUpdatedEvent [ id=%s, name=%s ]", id, name);
} }
@Override @Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) { public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.scopeUpdated(id, name, serverId, invalidations); cache.scopeUpdated(getId(), name, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ScopeUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ScopeUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public ScopeUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ScopeUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ScopeUpdatedEvent res = new ScopeUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -16,71 +16,42 @@
*/ */
package org.keycloak.models.cache.infinispan.authorization.stream; package org.keycloak.models.cache.infinispan.authorization.stream;
import java.io.Serializable; import org.infinispan.protostream.annotations.ProtoFactory;
import java.util.Map; import org.infinispan.protostream.annotations.ProtoField;
import java.util.function.Predicate; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.authorization.entities.InResource; import org.keycloak.models.cache.infinispan.authorization.entities.InResource;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException; import org.keycloak.marshalling.Marshalling;
import java.io.ObjectInput;
import java.io.ObjectOutput; import java.util.Map;
import org.infinispan.commons.marshall.Externalizer; import java.util.Objects;
import org.infinispan.commons.marshall.MarshallUtil; import java.util.function.Predicate;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
@SerializeWith(InResourcePredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.IN_RESOURCE_PREDICATE)
public class InResourcePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class InResourcePredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String resourceId; private final String resourceId;
public static InResourcePredicate create() { private InResourcePredicate(String resourceId) {
return new InResourcePredicate(); this.resourceId = Objects.requireNonNull(resourceId);
} }
public InResourcePredicate resource(String id) { @ProtoFactory
resourceId = id; public static InResourcePredicate create(String resourceId) {
return this; return new InResourcePredicate(resourceId);
}
@ProtoField(1)
String getResourceId() {
return resourceId;
} }
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof InResource inResource && resourceId.equals(inResource.getResourceId());
if (value == null) return false;
if (!(value instanceof InResource)) return false;
return resourceId.equals(((InResource)value).getResourceId());
} }
public static class ExternalizerImpl implements Externalizer<InResourcePredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InResourcePredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.resourceId, output);
}
@Override
public InResourcePredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InResourcePredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InResourcePredicate res = new InResourcePredicate();
res.resourceId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,70 +1,41 @@
package org.keycloak.models.cache.infinispan.authorization.stream; package org.keycloak.models.cache.infinispan.authorization.stream;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.entities.InResourceServer; import org.keycloak.models.cache.infinispan.authorization.entities.InResourceServer;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@SerializeWith(InResourceServerPredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.IN_RESOURCE_SERVER_PREDICATE)
public class InResourceServerPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class InResourceServerPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String serverId; private final String serverId;
public static InResourceServerPredicate create() { private InResourceServerPredicate(String serverId) {
return new InResourceServerPredicate(); this.serverId = Objects.requireNonNull(serverId);
} }
public InResourceServerPredicate resourceServer(String id) { @ProtoFactory
serverId = id; public static InResourceServerPredicate create(String serverId) {
return this; return new InResourceServerPredicate(serverId);
}
@ProtoField(1)
String getServerId() {
return serverId;
} }
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof InResourceServer inResourceServer && serverId.equals(inResourceServer.getResourceServerId());
if (value == null) return false;
if (!(value instanceof InResourceServer)) return false;
return serverId.equals(((InResourceServer)value).getResourceServerId());
} }
public static class ExternalizerImpl implements Externalizer<InResourceServerPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InResourceServerPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public InResourceServerPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InResourceServerPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InResourceServerPredicate res = new InResourceServerPredicate();
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,70 +1,41 @@
package org.keycloak.models.cache.infinispan.authorization.stream; package org.keycloak.models.cache.infinispan.authorization.stream;
import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.entities.InScope; import org.keycloak.models.cache.infinispan.authorization.entities.InScope;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@SerializeWith(InScopePredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.IN_SCOPE_PREDICATE)
public class InScopePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class InScopePredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String scopeId; private final String scopeId;
public static InScopePredicate create() { private InScopePredicate(String scopeId) {
return new InScopePredicate(); this.scopeId = Objects.requireNonNull(scopeId);
} }
public InScopePredicate scope(String id) { @ProtoFactory
scopeId = id; public static InScopePredicate create(String scopeId) {
return this; return new InScopePredicate(scopeId);
}
@ProtoField(1)
String getScopeId() {
return scopeId;
} }
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof InScope inScope && scopeId.equals(inScope.getScopeId());
if (value == null) return false;
if (!(value instanceof InScope)) return false;
return scopeId.equals(((InScope)value).getScopeId());
} }
public static class ExternalizerImpl implements Externalizer<InScopePredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InScopePredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.scopeId, output);
}
@Override
public InScopePredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InScopePredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InScopePredicate res = new InScopePredicate();
res.scopeId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -9,8 +9,8 @@ import java.io.Serializable;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class AbstractRevisioned implements Revisioned, Serializable, CachedObject { public class AbstractRevisioned implements Revisioned, CachedObject {
private String id; private final String id;
private Long revision; private Long revision;
private final long cacheTimestamp = Time.currentTimeMillis(); private final long cacheTimestamp = Time.currentTimeMillis();

View file

@ -28,7 +28,9 @@ import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.keycloak.common.enums.SslRequired; import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.ConcurrentMultivaluedHashMap;
import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.MultivaluedMap;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.AuthenticationFlowModel;
@ -122,8 +124,8 @@ public class CachedRealm extends AbstractExtendableRevisioned {
protected String masterAdminClient; protected String masterAdminClient;
protected List<RequiredCredentialModel> requiredCredentials; protected List<RequiredCredentialModel> requiredCredentials;
protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>(); protected MultivaluedMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
protected MultivaluedHashMap<String, ComponentModel> componentsByParentAndType = new MultivaluedHashMap<>(); protected MultivaluedMap<String, ComponentModel> componentsByParentAndType = new ConcurrentMultivaluedHashMap<>();
protected Map<String, ComponentModel> components; protected Map<String, ComponentModel> components;
protected List<IdentityProviderModel> identityProviders; protected List<IdentityProviderModel> identityProviders;
@ -417,11 +419,11 @@ public class CachedRealm extends AbstractExtendableRevisioned {
public boolean isVerifyEmail() { public boolean isVerifyEmail() {
return verifyEmail; return verifyEmail;
} }
public boolean isLoginWithEmailAllowed() { public boolean isLoginWithEmailAllowed() {
return loginWithEmailAllowed; return loginWithEmailAllowed;
} }
public boolean isDuplicateEmailsAllowed() { public boolean isDuplicateEmailsAllowed() {
return duplicateEmailsAllowed; return duplicateEmailsAllowed;
} }
@ -650,7 +652,7 @@ public class CachedRealm extends AbstractExtendableRevisioned {
public AuthenticationExecutionModel getAuthenticationExecutionByFlowId(String flowId) { public AuthenticationExecutionModel getAuthenticationExecutionByFlowId(String flowId) {
return executionsByFlowId.get(flowId); return executionsByFlowId.get(flowId);
} }
public Map<String, AuthenticationExecutionModel> getExecutionsById() { public Map<String, AuthenticationExecutionModel> getExecutionsById() {
return executionsById; return executionsById;
} }
@ -723,11 +725,11 @@ public class CachedRealm extends AbstractExtendableRevisioned {
return requiredActionProviderList; return requiredActionProviderList;
} }
public MultivaluedHashMap<String, ComponentModel> getComponentsByParent() { public MultivaluedMap<String, ComponentModel> getComponentsByParent() {
return componentsByParent; return componentsByParent;
} }
public MultivaluedHashMap<String, ComponentModel> getComponentsByParentAndType() { public MultivaluedMap<String, ComponentModel> getComponentsByParentAndType() {
return componentsByParentAndType; return componentsByParentAndType;
} }

View file

@ -16,115 +16,80 @@
*/ */
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import org.keycloak.cluster.ClusterEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.infinispan.commons.marshall.Externalizer; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.marshalling.Marshalling;
/** /**
* *
* @author hmlnarik * @author hmlnarik
*/ */
@SerializeWith(AuthenticationSessionAuthNoteUpdateEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.AUTHENTICATION_SESSION_AUTH_NOTE_UPDATE_EVENT)
public class AuthenticationSessionAuthNoteUpdateEvent implements ClusterEvent { public class AuthenticationSessionAuthNoteUpdateEvent implements ClusterEvent {
private String authSessionId; private final String authSessionId;
private String tabId; private final String tabId;
private String clientUUID; private final Map<String, String> authNotesFragment;
private Map<String, String> authNotesFragment; private AuthenticationSessionAuthNoteUpdateEvent(Map<String, String> authNotesFragment, String authSessionId, String tabId) {
this.authNotesFragment = Objects.requireNonNull(authNotesFragment);
this.authSessionId = Objects.requireNonNull(authSessionId);
this.tabId = Objects.requireNonNull(tabId);
}
/** /**
* Creates an instance of the event. * Creates an instance of the event.
* @param authSessionId *
* @param authNotesFragment
* @return Event. Note that {@code authNotesFragment} property is not thread safe which is fine for now. * @return Event. Note that {@code authNotesFragment} property is not thread safe which is fine for now.
*/ */
public static AuthenticationSessionAuthNoteUpdateEvent create(String authSessionId, String tabId, String clientUUID, Map<String, String> authNotesFragment) { @ProtoFactory
AuthenticationSessionAuthNoteUpdateEvent event = new AuthenticationSessionAuthNoteUpdateEvent(); public static AuthenticationSessionAuthNoteUpdateEvent create(String authSessionId, String tabId, Map<String, String> authNotesFragment) {
event.authSessionId = authSessionId; return new AuthenticationSessionAuthNoteUpdateEvent(authNotesFragment, authSessionId, tabId);
event.tabId = tabId;
event.clientUUID = clientUUID;
event.authNotesFragment = new LinkedHashMap<>(authNotesFragment);
return event;
} }
@ProtoField(1)
public String getAuthSessionId() { public String getAuthSessionId() {
return authSessionId; return authSessionId;
} }
@ProtoField(2)
public String getTabId() { public String getTabId() {
return tabId; return tabId;
} }
public String getClientUUID() { @ProtoField(value = 3, mapImplementation = LinkedHashMap.class)
return clientUUID;
}
public Map<String, String> getAuthNotesFragment() { public Map<String, String> getAuthNotesFragment() {
return authNotesFragment; return authNotesFragment;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (o == null || getClass() != o.getClass()) return false; return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthenticationSessionAuthNoteUpdateEvent that = (AuthenticationSessionAuthNoteUpdateEvent) o; AuthenticationSessionAuthNoteUpdateEvent that = (AuthenticationSessionAuthNoteUpdateEvent) o;
return Objects.equals(authSessionId, that.authSessionId) && Objects.equals(tabId, that.tabId) && Objects.equals(clientUUID, that.clientUUID); return Objects.equals(authSessionId, that.authSessionId) && Objects.equals(tabId, that.tabId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(authSessionId, tabId, clientUUID); return Objects.hash(authSessionId, tabId);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("AuthenticationSessionAuthNoteUpdateEvent [ authSessionId=%s, tabId=%s, clientUUID=%s, authNotesFragment=%s ]", return String.format("AuthenticationSessionAuthNoteUpdateEvent [ authSessionId=%s, tabId=%s, authNotesFragment=%s ]",
authSessionId, clientUUID, authNotesFragment); authSessionId, tabId, authNotesFragment);
} }
public static class ExternalizerImpl implements Externalizer<AuthenticationSessionAuthNoteUpdateEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, AuthenticationSessionAuthNoteUpdateEvent value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.authSessionId, output);
MarshallUtil.marshallString(value.tabId, output);
MarshallUtil.marshallString(value.clientUUID, output);
MarshallUtil.marshallMap(value.authNotesFragment, output);
}
@Override
public AuthenticationSessionAuthNoteUpdateEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public AuthenticationSessionAuthNoteUpdateEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return create(
MarshallUtil.unmarshallString(input),
MarshallUtil.unmarshallString(input),
MarshallUtil.unmarshallString(input),
MarshallUtil.<String, String, Map<String, String>>unmarshallMap(input, HashMap::new)
);
}
}
} }

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseClientEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String realmId;
BaseClientEvent(String clientUuid, String realmId) {
super(clientUuid);
this.realmId = Objects.requireNonNull(realmId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseClientEvent that = (BaseClientEvent) o;
return realmId.equals(that.realmId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + realmId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ realmId=%s, clientUuid=%s ]", getClass().getSimpleName(), realmId, getId());
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseClientScopeEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String realmId;
BaseClientScopeEvent(String clientScopeId, String realmId) {
super(clientScopeId);
this.realmId = Objects.requireNonNull(realmId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseClientScopeEvent that = (BaseClientScopeEvent) o;
return realmId.equals(that.realmId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + realmId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ clientScopeId=%s, realmId=%s ]", getClass().getSimpleName(), getId(), realmId);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseRealmEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String realmName;
BaseRealmEvent(String realmId, String realmName) {
super(realmId);
this.realmName = Objects.requireNonNull(realmName);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseRealmEvent that = (BaseRealmEvent) o;
return realmName.equals(that.realmName);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + realmName.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ realmId=%s, realmName=%s ]", getClass().getSimpleName(), getId(), realmName);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseRoleEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String containerId;
BaseRoleEvent(String roleId, String containerId) {
super(roleId);
this.containerId = Objects.requireNonNull(containerId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseRoleEvent that = (BaseRoleEvent) o;
return containerId.equals(that.containerId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + containerId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ roleId=%s, containerId=%s ]", getClass().getSimpleName(), getId(), containerId);
}
}

View file

@ -17,94 +17,30 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ClientAddedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.CLIENT_ADDED_EVENT)
public class ClientAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class ClientAddedEvent extends BaseClientEvent {
private String clientUuid; @ProtoFactory
private String clientId; ClientAddedEvent(String id, String realmId) {
private String realmId; super(id, realmId);
public static ClientAddedEvent create(String clientUuid, String clientId, String realmId) {
ClientAddedEvent event = new ClientAddedEvent();
event.clientUuid = clientUuid;
event.clientId = clientId;
event.realmId = realmId;
return event;
} }
@Override public static ClientAddedEvent create(String clientUuid, String realmId) {
public String getId() { return new ClientAddedEvent(clientUuid, realmId);
return clientUuid;
}
@Override
public String toString() {
return String.format("ClientAddedEvent [ realmId=%s, clientUuid=%s, clientId=%s ]", realmId, clientUuid, clientId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientAdded(realmId, invalidations); realmCache.clientAdded(realmId, invalidations);
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientAddedEvent that = (ClientAddedEvent) o;
return Objects.equals(clientUuid, that.clientUuid) && Objects.equals(clientId, that.clientId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientUuid, clientId, realmId);
}
public static class ExternalizerImpl implements Externalizer<ClientAddedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientAddedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientUuid, output);
MarshallUtil.marshallString(obj.clientId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientAddedEvent res = new ClientAddedEvent();
res.clientUuid = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -20,73 +20,56 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import org.jboss.logging.Logger; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ClientRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.CLIENT_REMOVED_EVENT)
public class ClientRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class ClientRemovedEvent extends BaseClientEvent {
private String clientUuid; @ProtoField(3)
private String clientId; final String clientId;
private String realmId;
// roleId -> roleName // roleId -> roleName
private Map<String, String> clientRoles; @ProtoField(4)
private static final Logger log = Logger.getLogger(ClientRemovedEvent.class); final Map<String, String> clientRoles;
@ProtoFactory
ClientRemovedEvent(String id, String realmId, String clientId, Map<String, String> clientRoles) {
super(id, realmId);
this.clientId = Objects.requireNonNull(clientId);
this.clientRoles = Objects.requireNonNull(clientRoles);
}
public static ClientRemovedEvent create(ClientModel client) { public static ClientRemovedEvent create(ClientModel client) {
log.tracev("Created; clientId={0}", client.getClientId()); var clientRoles = client.getRolesStream().collect(Collectors.toMap(RoleModel::getId, RoleModel::getName));
return new ClientRemovedEvent(client.getId(), client.getClientId(), client.getRealm().getId(), clientRoles);
ClientRemovedEvent event = new ClientRemovedEvent();
event.realmId = client.getRealm().getId();
event.clientUuid = client.getId();
event.clientId = client.getClientId();
event.clientRoles = client.getRolesStream().collect(Collectors.toMap(RoleModel::getId, RoleModel::getName));
return event;
} }
@Override
protected void finalize() throws Throwable {
log.tracev("Finalized; clientId={0}", clientId);
super.finalize();
}
@Override
public String getId() {
return clientUuid;
}
@Override @Override
public String toString() { public String toString() {
return String.format("ClientRemovedEvent [ realmId=%s, clientUuid=%s, clientId=%s, clientRoleIds=%s ]", realmId, clientUuid, clientId, clientRoles); return String.format("ClientRemovedEvent [ realmId=%s, clientUuid=%s, clientId=%s, clientRoleIds=%s ]", realmId, getId(), clientId, clientRoles);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientRemoval(realmId, clientUuid, clientId, invalidations); realmCache.clientRemoval(realmId, getId(), clientId, invalidations);
// Separate iteration for all client roles to invalidate records dependent on them // Separate iteration for all client roles to invalidate records dependent on them
for (Map.Entry<String, String> clientRole : clientRoles.entrySet()) { for (Map.Entry<String, String> clientRole : clientRoles.entrySet()) {
String roleId = clientRole.getKey(); String roleId = clientRole.getKey();
String roleName = clientRole.getValue(); String roleName = clientRole.getValue();
realmCache.roleRemoval(roleId, roleName, clientUuid, invalidations); realmCache.roleRemoval(roleId, roleName, getId(), invalidations);
} }
} }
@ -96,56 +79,15 @@ public class ClientRemovedEvent extends InvalidationEvent implements RealmCacheI
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
ClientRemovedEvent that = (ClientRemovedEvent) o; ClientRemovedEvent that = (ClientRemovedEvent) o;
boolean equals = Objects.equals(clientUuid, that.clientUuid) && return clientId.equals(that.clientId) &&
Objects.equals(clientId, that.clientId) && clientRoles.equals(that.clientRoles);
Objects.equals(realmId, that.realmId) &&
Objects.equals(clientRoles, that.clientRoles);
log.tracev("Equals; clientId={0}, equals={1}", clientId, equals);
return equals;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), clientUuid, clientId, realmId, clientRoles); int result = super.hashCode();
} result = 31 * result + clientId.hashCode();
result = 31 * result + clientRoles.hashCode();
public static class ExternalizerImpl implements Externalizer<ClientRemovedEvent> { return result;
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientUuid, output);
MarshallUtil.marshallString(obj.clientId, output);
MarshallUtil.marshallString(obj.realmId, output);
KeycloakMarshallUtil.writeMap(obj.clientRoles, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
log.tracev("Write; clientId={0}", obj.clientId);
}
@Override
public ClientRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientRemovedEvent res = new ClientRemovedEvent();
res.clientUuid = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.clientRoles = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT,
size -> new ConcurrentHashMap<>(size));
log.tracev("Read; clientId={0}", res.clientId);
return res;
}
} }
} }

View file

@ -17,87 +17,27 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
@SerializeWith(ClientScopeAddedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.CLIENT_SCOPE_ADDED_EVENT)
public class ClientScopeAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class ClientScopeAddedEvent extends BaseClientScopeEvent {
private String clientScopeId; @ProtoFactory
private String realmId; ClientScopeAddedEvent(String id, String realmId) {
super(id, realmId);
}
public static ClientScopeAddedEvent create(String clientScopeId, String realmId) { public static ClientScopeAddedEvent create(String clientScopeId, String realmId) {
ClientScopeAddedEvent event = new ClientScopeAddedEvent(); return new ClientScopeAddedEvent(clientScopeId, realmId);
event.clientScopeId = clientScopeId;
event.realmId = realmId;
return event;
}
@Override
public String getId() {
return clientScopeId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientScopeAddedEvent that = (ClientScopeAddedEvent) o;
return Objects.equals(clientScopeId, that.clientScopeId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientScopeId, realmId);
}
@Override
public String toString() {
return String.format("ClientScopeAddedEvent [ clientScopeId=%s, realmId=%s ]", clientScopeId, realmId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientScopeAdded(realmId, invalidations); realmCache.clientScopeAdded(realmId, invalidations);
} }
public static class ExternalizerImpl implements Externalizer<ClientScopeAddedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientScopeAddedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientScopeId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientScopeAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientScopeAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientScopeAddedEvent res = new ClientScopeAddedEvent();
res.clientScopeId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -17,88 +17,27 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer; @ProtoTypeId(Marshalling.CLIENT_SCOPE_REMOVED_EVENT)
import org.infinispan.commons.marshall.MarshallUtil; public class ClientScopeRemovedEvent extends BaseClientScopeEvent {
import org.infinispan.commons.marshall.SerializeWith;
@SerializeWith(ClientScopeRemovedEvent.ExternalizerImpl.class) @ProtoFactory
public class ClientScopeRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { ClientScopeRemovedEvent(String id, String realmId) {
super(id, realmId);
private String clientScopeId; }
private String realmId;
public static ClientScopeRemovedEvent create(String clientScopeId, String realmId) { public static ClientScopeRemovedEvent create(String clientScopeId, String realmId) {
ClientScopeRemovedEvent event = new ClientScopeRemovedEvent(); return new ClientScopeRemovedEvent(clientScopeId, realmId);
event.clientScopeId = clientScopeId;
event.realmId = realmId;
return event;
}
@Override
public String getId() {
return clientScopeId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientScopeRemovedEvent that = (ClientScopeRemovedEvent) o;
return Objects.equals(clientScopeId, that.clientScopeId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientScopeId, realmId);
}
@Override
public String toString() {
return String.format("ClientScopeRemovedEvent [ clientScopeId=%s, realmId=%s ]", clientScopeId, realmId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientScopeRemoval(realmId, invalidations); realmCache.clientScopeRemoval(realmId, invalidations);
} }
public static class ExternalizerImpl implements Externalizer<ClientScopeRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientScopeRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientScopeId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientScopeRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientScopeRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientScopeRemovedEvent res = new ClientScopeRemovedEvent();
res.clientScopeId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,106 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* TODO Leave the name ClientTemplateEvent just due the backwards compatibility of infinispan migration. See if can be renamed based on
* rolling upgrades plan...
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ClientTemplateEvent.ExternalizerImpl.class)
public class ClientTemplateEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String clientTemplateId;
public static ClientTemplateEvent create(String clientTemplateId) {
ClientTemplateEvent event = new ClientTemplateEvent();
event.clientTemplateId = clientTemplateId;
return event;
}
@Override
public String getId() {
return clientTemplateId;
}
@Override
public String toString() {
return "ClientTemplateEvent [ " + clientTemplateId + " ]";
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
// Nothing. ID was already invalidated
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientTemplateEvent that = (ClientTemplateEvent) o;
return Objects.equals(clientTemplateId, that.clientTemplateId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientTemplateId);
}
public static class ExternalizerImpl implements Externalizer<ClientTemplateEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientTemplateEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientTemplateId, output);
}
@Override
public ClientTemplateEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientTemplateEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientTemplateEvent res = new ClientTemplateEvent();
res.clientTemplateId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -17,94 +17,40 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(ClientUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.CLIENT_UPDATED_EVENT)
public class ClientUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class ClientUpdatedEvent extends BaseClientEvent {
private String clientUuid; @ProtoField(3)
private String clientId; final String clientId;
private String realmId;
public static ClientUpdatedEvent create(String clientUuid, String clientId, String realmId) { @ProtoFactory
ClientUpdatedEvent event = new ClientUpdatedEvent(); ClientUpdatedEvent(String id, String realmId, String clientId) {
event.clientUuid = clientUuid; super(id, realmId);
event.clientId = clientId; this.clientId = clientId;
event.realmId = realmId;
return event;
} }
@Override public static ClientUpdatedEvent create(String clientUuid, String clientId, String realmId) {
public String getId() { return new ClientUpdatedEvent(clientUuid, realmId, clientId);
return clientUuid;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("ClientUpdatedEvent [ realmId=%s, clientUuid=%s, clientId=%s ]", realmId, clientUuid, clientId); return String.format("ClientUpdatedEvent [ realmId=%s, clientUuid=%s, clientId=%s ]", realmId, getId(), clientId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientUpdated(realmId, clientUuid, clientId, invalidations); realmCache.clientUpdated(realmId, getId(), clientId, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientUpdatedEvent that = (ClientUpdatedEvent) o;
return Objects.equals(clientUuid, that.clientUuid) && Objects.equals(clientId, that.clientId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientUuid, clientId, realmId);
}
public static class ExternalizerImpl implements Externalizer<ClientUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientUuid, output);
MarshallUtil.marshallString(obj.clientId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientUpdatedEvent res = new ClientUpdatedEvent();
res.clientUuid = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -20,41 +20,42 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(GroupAddedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.GROUP_ADDED_EVENT)
public class GroupAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class GroupAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId; @ProtoField(2)
private String realmId; final String realmId;
private String parentId; @ProtoField(3)
final String parentId; //parentId may be null
public static GroupAddedEvent create(String groupId, String parentId, String realmId) { private GroupAddedEvent(String groupId, String realmId, String parentId) {
GroupAddedEvent event = new GroupAddedEvent(); super(groupId);
event.realmId = realmId; this.realmId = Objects.requireNonNull(realmId);
event.parentId = parentId; this.parentId = parentId;
event.groupId = groupId;
return event;
} }
@Override @ProtoFactory
public String getId() { static GroupAddedEvent protoFactory(String id, String realmId, String parentId) {
return groupId; return new GroupAddedEvent(id, realmId, Marshalling.emptyStringToNull(parentId));
}
public static GroupAddedEvent create(String groupId, String parentId, String realmId) {
return new GroupAddedEvent(groupId, realmId, parentId);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("GroupAddedEvent [ realmId=%s, groupId=%s ]", realmId, groupId); return String.format("GroupAddedEvent [ realmId=%s, groupId=%s ]", realmId, getId());
} }
@Override @Override
@ -70,56 +71,16 @@ public class GroupAddedEvent extends InvalidationEvent implements RealmCacheInva
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
GroupAddedEvent that = (GroupAddedEvent) o; GroupAddedEvent that = (GroupAddedEvent) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(realmId, that.realmId) && Objects.equals(parentId, that.parentId); return realmId.equals(that.realmId) && Objects.equals(parentId, that.parentId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), groupId, realmId, parentId); int result = super.hashCode();
} result = 31 * result + realmId.hashCode();
result = 31 * result + Objects.hashCode(parentId);
public static class ExternalizerImpl implements Externalizer<GroupAddedEvent> { return result;
private static final int VERSION_1 = 1;
private static final int VERSION_2 = 2;
@Override
public void writeObject(ObjectOutput output, GroupAddedEvent obj) throws IOException {
output.writeByte(VERSION_2);
MarshallUtil.marshallString(obj.groupId, output);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.parentId, output);
}
@Override
public GroupAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
case VERSION_2:
return readObjectVersion2(input);
default:
throw new IOException("Unknown version");
}
}
public GroupAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupAddedEvent res = new GroupAddedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
public GroupAddedEvent readObjectVersion2(ObjectInput input) throws IOException, ClassNotFoundException {
GroupAddedEvent res = new GroupAddedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.parentId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -20,49 +20,51 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(GroupMovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.GROUP_MOVED_EVENT)
public class GroupMovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class GroupMovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId; @ProtoField(2)
private String newParentId; // null if moving to top-level final String newParentId; // null if moving to top-level
private String oldParentId; // null if moving from top-level @ProtoField(3)
private String realmId; final String oldParentId; // null if moving from top-level
@ProtoField(4)
final String realmId;
public static GroupMovedEvent create(GroupModel group, GroupModel toParent, String realmId) { private GroupMovedEvent(String groupId, String newParentId, String oldParentId, String realmId) {
GroupMovedEvent event = new GroupMovedEvent(); super(groupId);
event.realmId = realmId; this.newParentId = newParentId;
event.groupId = group.getId(); this.oldParentId = oldParentId;
event.oldParentId = group.getParentId(); this.realmId = Objects.requireNonNull(realmId);
event.newParentId = toParent==null ? null : toParent.getId();
return event;
} }
@Override @ProtoFactory
public String getId() { static GroupMovedEvent protoFactory(String id, String newParentId, String oldParentId, String realmId) {
return groupId; return new GroupMovedEvent(id, Marshalling.emptyStringToNull(newParentId), Marshalling.emptyStringToNull(oldParentId), realmId);
}
public static GroupMovedEvent create(GroupModel group, GroupModel toParent, String realmId) {
return new GroupMovedEvent(group.getId(), group.getId(), toParent == null ? null : toParent.getId(), realmId);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("GroupMovedEvent [ realmId=%s, groupId=%s, newParentId=%s, oldParentId=%s ]", realmId, groupId, newParentId, oldParentId); return String.format("GroupMovedEvent [ realmId=%s, groupId=%s, newParentId=%s, oldParentId=%s ]", realmId, getId(), newParentId, oldParentId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.groupQueriesInvalidations(realmId, invalidations); realmCache.groupQueriesInvalidations(realmId, invalidations);
realmCache.groupNameInvalidations(groupId, invalidations); realmCache.groupNameInvalidations(getId(), invalidations);
if (newParentId != null) { if (newParentId != null) {
invalidations.add(newParentId); invalidations.add(newParentId);
} }
@ -76,47 +78,19 @@ public class GroupMovedEvent extends InvalidationEvent implements RealmCacheInva
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
GroupMovedEvent that = (GroupMovedEvent) o; GroupMovedEvent that = (GroupMovedEvent) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(newParentId, that.newParentId) && Objects.equals(oldParentId, that.oldParentId) && Objects.equals(realmId, that.realmId); return Objects.equals(newParentId, that.newParentId) &&
Objects.equals(oldParentId, that.oldParentId) &&
realmId.equals(that.realmId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), groupId, newParentId, oldParentId, realmId); int result = super.hashCode();
} result = 31 * result + Objects.hashCode(newParentId);
result = 31 * result + Objects.hashCode(oldParentId);
public static class ExternalizerImpl implements Externalizer<GroupMovedEvent> { result = 31 * result + realmId.hashCode();
return result;
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupMovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.groupId, output);
MarshallUtil.marshallString(obj.newParentId, output);
MarshallUtil.marshallString(obj.oldParentId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public GroupMovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupMovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupMovedEvent res = new GroupMovedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
res.newParentId = MarshallUtil.unmarshallString(input);
res.oldParentId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -20,47 +20,48 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(GroupRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.GROUP_REMOVED_EVENT)
public class GroupRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class GroupRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId; @ProtoField(2)
private String parentId; final String realmId;
private String realmId; @ProtoField(3)
final String parentId;
public static GroupRemovedEvent create(GroupModel group, String realmId) { public GroupRemovedEvent(String groupId, String realmId, String parentId) {
GroupRemovedEvent event = new GroupRemovedEvent(); super(groupId);
event.realmId = realmId; this.realmId = Objects.requireNonNull(realmId);
event.groupId = group.getId(); this.parentId = parentId;
event.parentId = group.getParentId();
return event;
} }
@Override @ProtoFactory
public String getId() { static GroupRemovedEvent protoFactory(String id, String realmId, String parentId) {
return groupId; return new GroupRemovedEvent(id, realmId, Marshalling.emptyStringToNull(parentId));
}
public static GroupRemovedEvent create(GroupModel group, String realmId) {
return new GroupRemovedEvent(group.getId(), realmId, group.getParentId());
} }
@Override @Override
public String toString() { public String toString() {
return String.format("GroupRemovedEvent [ realmId=%s, groupId=%s, parentId=%s ]", realmId, groupId, parentId); return String.format("GroupRemovedEvent [ realmId=%s, groupId=%s, parentId=%s ]", realmId, getId(), parentId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.groupQueriesInvalidations(realmId, invalidations); realmCache.groupQueriesInvalidations(realmId, invalidations);
realmCache.groupNameInvalidations(groupId, invalidations); realmCache.groupNameInvalidations(getId(), invalidations);
if (parentId != null) { if (parentId != null) {
invalidations.add(parentId); invalidations.add(parentId);
} }
@ -71,45 +72,16 @@ public class GroupRemovedEvent extends InvalidationEvent implements RealmCacheIn
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
GroupRemovedEvent that = (GroupRemovedEvent) o; GroupRemovedEvent that = (GroupRemovedEvent) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(parentId, that.parentId) && Objects.equals(realmId, that.realmId); return realmId.equals(that.realmId) && Objects.equals(parentId, that.parentId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), groupId, parentId, realmId); int result = super.hashCode();
} result = 31 * result + realmId.hashCode();
result = 31 * result + Objects.hashCode(parentId);
public static class ExternalizerImpl implements Externalizer<GroupRemovedEvent> { return result;
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.groupId, output);
MarshallUtil.marshallString(obj.parentId, output);
}
@Override
public GroupRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupRemovedEvent res = new GroupRemovedEvent();
res.realmId = MarshallUtil.unmarshallString(input);
res.groupId = MarshallUtil.unmarshallString(input);
res.parentId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -19,70 +19,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(GroupUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.GROUP_UPDATED_EVENT)
public class GroupUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class GroupUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId; @ProtoFactory
GroupUpdatedEvent(String id) {
super(id);
}
public static GroupUpdatedEvent create(String groupId) { public static GroupUpdatedEvent create(String groupId) {
GroupUpdatedEvent event = new GroupUpdatedEvent(); return new GroupUpdatedEvent(groupId);
event.groupId = groupId;
return event;
} }
@Override
public String getId() {
return groupId;
}
@Override @Override
public String toString() { public String toString() {
return "GroupUpdatedEvent [ " + groupId + " ]"; return "GroupUpdatedEvent [ " + getId() + " ]";
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.groupNameInvalidations(groupId, invalidations); realmCache.groupNameInvalidations(getId(), invalidations);
} }
public static class ExternalizerImpl implements Externalizer<GroupUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.groupId, output);
}
@Override
public GroupUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupUpdatedEvent res = new GroupUpdatedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -17,6 +17,9 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.cluster.ClusterEvent; import org.keycloak.cluster.ClusterEvent;
/** /**
@ -24,7 +27,16 @@ import org.keycloak.cluster.ClusterEvent;
*/ */
public abstract class InvalidationEvent implements ClusterEvent { public abstract class InvalidationEvent implements ClusterEvent {
public abstract String getId(); private final String id;
protected InvalidationEvent(String id) {
this.id = Objects.requireNonNull(id);
}
@ProtoField(1)
public final String getId() {
return id;
}
@Override @Override
public int hashCode() { public int hashCode() {
@ -37,7 +49,6 @@ public abstract class InvalidationEvent implements ClusterEvent {
if (!obj.getClass().equals(this.getClass())) return false; if (!obj.getClass().equals(this.getClass())) return false;
InvalidationEvent that = (InvalidationEvent) obj; InvalidationEvent that = (InvalidationEvent) obj;
if (!that.getId().equals(getId())) return false; return that.getId().equals(getId());
return true;
} }
} }

View file

@ -17,90 +17,30 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RealmRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.REALM_REMOVED_EVENT)
public class RealmRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class RealmRemovedEvent extends BaseRealmEvent {
private String realmId; @ProtoFactory
private String realmName; RealmRemovedEvent(String id, String realmName) {
super(id, realmName);
}
public static RealmRemovedEvent create(String realmId, String realmName) { public static RealmRemovedEvent create(String realmId, String realmName) {
RealmRemovedEvent event = new RealmRemovedEvent(); return new RealmRemovedEvent(realmId, realmName);
event.realmId = realmId;
event.realmName = realmName;
return event;
}
@Override
public String getId() {
return realmId;
}
@Override
public String toString() {
return String.format("RealmRemovedEvent [ realmId=%s, realmName=%s ]", realmId, realmName);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.realmRemoval(realmId, realmName, invalidations); realmCache.realmRemoval(getId(), realmName, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RealmRemovedEvent that = (RealmRemovedEvent) o;
return Objects.equals(realmId, that.realmId) && Objects.equals(realmName, that.realmName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), realmId, realmName);
}
public static class ExternalizerImpl implements Externalizer<RealmRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RealmRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.realmName, output);
}
@Override
public RealmRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RealmRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RealmRemovedEvent res = new RealmRemovedEvent();
res.realmId = MarshallUtil.unmarshallString(input);
res.realmName = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,90 +17,30 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RealmUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.REALM_UPDATED_EVENT)
public class RealmUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class RealmUpdatedEvent extends BaseRealmEvent {
private String realmId; @ProtoFactory
private String realmName; RealmUpdatedEvent(String id, String realmName) {
super(id, realmName);
}
public static RealmUpdatedEvent create(String realmId, String realmName) { public static RealmUpdatedEvent create(String realmId, String realmName) {
RealmUpdatedEvent event = new RealmUpdatedEvent(); return new RealmUpdatedEvent(realmId, realmName);
event.realmId = realmId;
event.realmName = realmName;
return event;
}
@Override
public String getId() {
return realmId;
}
@Override
public String toString() {
return String.format("RealmUpdatedEvent [ realmId=%s, realmName=%s ]", realmId, realmName);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.realmUpdated(realmId, realmName, invalidations); realmCache.realmUpdated(getId(), realmName, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RealmUpdatedEvent that = (RealmUpdatedEvent) o;
return Objects.equals(realmId, that.realmId) && Objects.equals(realmName, that.realmName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), realmId, realmName);
}
public static class ExternalizerImpl implements Externalizer<RealmUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RealmUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.realmName, output);
}
@Override
public RealmUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RealmUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RealmUpdatedEvent res = new RealmUpdatedEvent();
res.realmId = MarshallUtil.unmarshallString(input);
res.realmName = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -17,90 +17,30 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RoleAddedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.ROLE_ADDED_EVENT)
public class RoleAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class RoleAddedEvent extends BaseRoleEvent {
private String roleId; @ProtoFactory
private String containerId; RoleAddedEvent(String id, String containerId) {
super(id, containerId);
}
public static RoleAddedEvent create(String roleId, String containerId) { public static RoleAddedEvent create(String roleId, String containerId) {
RoleAddedEvent event = new RoleAddedEvent(); return new RoleAddedEvent(roleId, containerId);
event.roleId = roleId;
event.containerId = containerId;
return event;
}
@Override
public String getId() {
return roleId;
}
@Override
public String toString() {
return String.format("RoleAddedEvent [ roleId=%s, containerId=%s ]", roleId, containerId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.roleAdded(containerId, invalidations); realmCache.roleAdded(containerId, invalidations);
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RoleAddedEvent that = (RoleAddedEvent) o;
return Objects.equals(roleId, that.roleId) && Objects.equals(containerId, that.containerId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), roleId, containerId);
}
public static class ExternalizerImpl implements Externalizer<RoleAddedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RoleAddedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.roleId, output);
MarshallUtil.marshallString(obj.containerId, output);
}
@Override
public RoleAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RoleAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RoleAddedEvent res = new RoleAddedEvent();
res.roleId = MarshallUtil.unmarshallString(input);
res.containerId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -20,45 +20,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RoleRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.ROLE_REMOVED_EVENT)
public class RoleRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class RoleRemovedEvent extends BaseRoleEvent {
private String roleId; @ProtoField(3)
private String roleName; final String roleName;
private String containerId;
@ProtoFactory
RoleRemovedEvent(String id, String containerId, String roleName) {
super(id, containerId);
this.roleName = Objects.requireNonNull(roleName);
}
public static RoleRemovedEvent create(String roleId, String roleName, String containerId) { public static RoleRemovedEvent create(String roleId, String roleName, String containerId) {
RoleRemovedEvent event = new RoleRemovedEvent(); return new RoleRemovedEvent(roleId, containerId, roleName);
event.roleId = roleId;
event.roleName = roleName;
event.containerId = containerId;
return event;
}
@Override
public String getId() {
return roleId;
}
@Override
public String toString() {
return String.format("RoleRemovedEvent [ roleId=%s, containerId=%s ]", roleId, containerId);
} }
@Override @Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) { public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.roleRemoval(roleId, roleName, containerId, invalidations); realmCache.roleRemoval(getId(), roleName, containerId, invalidations);
} }
@Override @Override
@ -66,45 +55,15 @@ public class RoleRemovedEvent extends InvalidationEvent implements RealmCacheInv
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
RoleRemovedEvent that = (RoleRemovedEvent) o; RoleRemovedEvent that = (RoleRemovedEvent) o;
return Objects.equals(roleId, that.roleId) && Objects.equals(roleName, that.roleName) && Objects.equals(containerId, that.containerId); return roleName.equals(that.roleName);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), roleId, roleName, containerId); int result = super.hashCode();
} result = 31 * result + roleName.hashCode();
return result;
public static class ExternalizerImpl implements Externalizer<RoleRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RoleRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.roleId, output);
MarshallUtil.marshallString(obj.roleName, output);
MarshallUtil.marshallString(obj.containerId, output);
}
@Override
public RoleRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RoleRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RoleRemovedEvent res = new RoleRemovedEvent();
res.roleId = MarshallUtil.unmarshallString(input);
res.roleName = MarshallUtil.unmarshallString(input);
res.containerId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -20,40 +20,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager; import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RoleUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.ROLE_UPDATED_EVENT)
public class RoleUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent { public class RoleUpdatedEvent extends BaseRoleEvent {
private String roleId; @ProtoField(3)
private String roleName; final String roleName;
private String containerId;
public static RoleUpdatedEvent create(String roleId, String roleName, String containerId) { @ProtoFactory
RoleUpdatedEvent event = new RoleUpdatedEvent(); RoleUpdatedEvent(String id, String containerId, String roleName) {
event.roleId = roleId; super(id, containerId);
event.roleName = roleName; this.roleName = Objects.requireNonNull(roleName);
event.containerId = containerId;
return event;
} }
@Override public static RoleUpdatedEvent create(String roleId, String roleName, String containerId) {
public String getId() { return new RoleUpdatedEvent(roleId, containerId, roleName);
return roleId;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("RoleUpdatedEvent [ roleId=%s, roleName=%s, containerId=%s ]", roleId, roleName, containerId); return String.format("RoleUpdatedEvent [ roleId=%s, roleName=%s, containerId=%s ]", getId(), roleName, containerId);
} }
@Override @Override
@ -66,45 +60,15 @@ public class RoleUpdatedEvent extends InvalidationEvent implements RealmCacheInv
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
RoleUpdatedEvent that = (RoleUpdatedEvent) o; RoleUpdatedEvent that = (RoleUpdatedEvent) o;
return Objects.equals(roleId, that.roleId) && Objects.equals(roleName, that.roleName) && Objects.equals(containerId, that.containerId); return roleName.equals(that.roleName);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), roleId, roleName, containerId); int result = super.hashCode();
} result = 31 * result + roleName.hashCode();
return result;
public static class ExternalizerImpl implements Externalizer<RoleUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RoleUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.roleId, output);
MarshallUtil.marshallString(obj.roleName, output);
MarshallUtil.marshallString(obj.containerId, output);
}
@Override
public RoleUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RoleUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RoleUpdatedEvent res = new RoleUpdatedEvent();
res.roleId = MarshallUtil.unmarshallString(input);
res.roleName = MarshallUtil.unmarshallString(input);
res.containerId = MarshallUtil.unmarshallString(input);
return res;
}
} }
} }

View file

@ -19,69 +19,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager; import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(UserCacheRealmInvalidationEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.USER_CACHE_REALM_INVALIDATION_EVENT)
public class UserCacheRealmInvalidationEvent extends InvalidationEvent implements UserCacheInvalidationEvent { public class UserCacheRealmInvalidationEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String realmId; private UserCacheRealmInvalidationEvent(String id) {
super(id);
public static UserCacheRealmInvalidationEvent create(String realmId) {
UserCacheRealmInvalidationEvent event = new UserCacheRealmInvalidationEvent();
event.realmId = realmId;
return event;
} }
@Override @ProtoFactory
public String getId() { public static UserCacheRealmInvalidationEvent create(String id) {
return realmId; // Just a placeholder return new UserCacheRealmInvalidationEvent(id);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("UserCacheRealmInvalidationEvent [ realmId=%s ]", realmId); return String.format("UserCacheRealmInvalidationEvent [ realmId=%s ]", getId());
} }
@Override @Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) { public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.invalidateRealmUsers(realmId, invalidations); userCache.invalidateRealmUsers(getId(), invalidations);
} }
public static class ExternalizerImpl implements Externalizer<UserCacheRealmInvalidationEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserCacheRealmInvalidationEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public UserCacheRealmInvalidationEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserCacheRealmInvalidationEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserCacheRealmInvalidationEvent res = new UserCacheRealmInvalidationEvent();
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -19,69 +19,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager; import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(UserConsentsUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.USER_CONSENTS_UPDATED_EVENT)
public class UserConsentsUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent { public class UserConsentsUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId; private UserConsentsUpdatedEvent(String id) {
super(id);
public static UserConsentsUpdatedEvent create(String userId) {
UserConsentsUpdatedEvent event = new UserConsentsUpdatedEvent();
event.userId = userId;
return event;
} }
@Override @ProtoFactory
public String getId() { public static UserConsentsUpdatedEvent create(String id) {
return userId; return new UserConsentsUpdatedEvent(id);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("UserConsentsUpdatedEvent [ userId=%s ]", userId); return String.format("UserConsentsUpdatedEvent [ userId=%s ]", getId());
} }
@Override @Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) { public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.consentInvalidation(userId, invalidations); userCache.consentInvalidation(getId(), invalidations);
} }
public static class ExternalizerImpl implements Externalizer<UserConsentsUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserConsentsUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
}
@Override
public UserConsentsUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserConsentsUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserConsentsUpdatedEvent res = new UserConsentsUpdatedEvent();
res.userId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -20,62 +20,65 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.cache.infinispan.UserCacheManager; import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(UserFederationLinkRemovedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.USER_FEDERATION_LINK_REMOVED_EVENT)
public class UserFederationLinkRemovedEvent extends InvalidationEvent implements UserCacheInvalidationEvent { public class UserFederationLinkRemovedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId; final String realmId;
private String realmId; final String identityProviderId;
private String identityProviderId; final String socialUserId;
private String socialUserId;
private UserFederationLinkRemovedEvent(String id, String realmId, String identityProviderId, String socialUserId) {
super(id);
this.realmId = Objects.requireNonNull(realmId);
// may be null
this.identityProviderId = identityProviderId;
this.socialUserId = socialUserId;
}
public static UserFederationLinkRemovedEvent create(String userId, String realmId, FederatedIdentityModel socialLink) { public static UserFederationLinkRemovedEvent create(String userId, String realmId, FederatedIdentityModel socialLink) {
UserFederationLinkRemovedEvent event = new UserFederationLinkRemovedEvent(); String identityProviderId = socialLink == null ? null : socialLink.getIdentityProvider();
event.userId = userId; String socialUserId = socialLink == null ? null : socialLink.getUserId();
event.realmId = realmId; return new UserFederationLinkRemovedEvent(userId, realmId, identityProviderId, socialUserId);
if (socialLink != null) {
event.identityProviderId = socialLink.getIdentityProvider();
event.socialUserId = socialLink.getUserId();
}
return event;
} }
@Override @ProtoFactory
public String getId() { static UserFederationLinkRemovedEvent protoFactory(String id, String realmId, String identityProviderId, String socialUserId) {
return userId; return new UserFederationLinkRemovedEvent(id, realmId, Marshalling.emptyStringToNull(identityProviderId), Marshalling.emptyStringToNull(socialUserId));
} }
@ProtoField(2)
public String getRealmId() { public String getRealmId() {
return realmId; return realmId;
} }
@ProtoField(3)
public String getIdentityProviderId() { public String getIdentityProviderId() {
return identityProviderId; return identityProviderId;
} }
@ProtoField(4)
public String getSocialUserId() { public String getSocialUserId() {
return socialUserId; return socialUserId;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("UserFederationLinkRemovedEvent [ userId=%s, identityProviderId=%s, socialUserId=%s ]", userId, identityProviderId, socialUserId); return String.format("UserFederationLinkRemovedEvent [ userId=%s, identityProviderId=%s, socialUserId=%s ]", getId(), identityProviderId, socialUserId);
} }
@Override @Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) { public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.federatedIdentityLinkRemovedInvalidation(userId, realmId, identityProviderId, socialUserId, invalidations); userCache.federatedIdentityLinkRemovedInvalidation(getId(), realmId, identityProviderId, socialUserId, invalidations);
} }
@Override @Override
@ -84,46 +87,12 @@ public class UserFederationLinkRemovedEvent extends InvalidationEvent implements
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
UserFederationLinkRemovedEvent that = (UserFederationLinkRemovedEvent) o; UserFederationLinkRemovedEvent that = (UserFederationLinkRemovedEvent) o;
return Objects.equals(userId, that.userId) && Objects.equals(realmId, that.realmId) && Objects.equals(identityProviderId, that.identityProviderId) && Objects.equals(socialUserId, that.socialUserId); return Objects.equals(realmId, that.realmId) && Objects.equals(identityProviderId, that.identityProviderId) && Objects.equals(socialUserId, that.socialUserId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), userId, realmId, identityProviderId, socialUserId); return Objects.hash(super.hashCode(), realmId, identityProviderId, socialUserId);
} }
public static class ExternalizerImpl implements Externalizer<UserFederationLinkRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserFederationLinkRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.identityProviderId, output);
MarshallUtil.marshallString(obj.socialUserId, output);
}
@Override
public UserFederationLinkRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserFederationLinkRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserFederationLinkRemovedEvent res = new UserFederationLinkRemovedEvent();
res.userId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.identityProviderId = MarshallUtil.unmarshallString(input);
res.socialUserId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -18,69 +18,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager; import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(UserFederationLinkUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.USER_FEDERATION_LINK_UPDATED_EVENT)
public class UserFederationLinkUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent { public class UserFederationLinkUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId; private UserFederationLinkUpdatedEvent(String id) {
super(id);
public static UserFederationLinkUpdatedEvent create(String userId) {
UserFederationLinkUpdatedEvent event = new UserFederationLinkUpdatedEvent();
event.userId = userId;
return event;
} }
@Override @ProtoFactory
public String getId() { public static UserFederationLinkUpdatedEvent create(String id) {
return userId; return new UserFederationLinkUpdatedEvent(id);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("UserFederationLinkUpdatedEvent [ userId=%s ]", userId); return String.format("UserFederationLinkUpdatedEvent [ userId=%s ]", getId());
} }
@Override @Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) { public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.federatedIdentityLinkUpdatedInvalidation(userId, invalidations); userCache.federatedIdentityLinkUpdatedInvalidation(getId(), invalidations);
} }
public static class ExternalizerImpl implements Externalizer<UserFederationLinkUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserFederationLinkUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
}
@Override
public UserFederationLinkUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserFederationLinkUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserFederationLinkUpdatedEvent res = new UserFederationLinkUpdatedEvent();
res.userId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -21,54 +21,56 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.cache.infinispan.UserCacheManager;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.infinispan.commons.marshall.Externalizer; import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.cache.infinispan.UserCacheManager;
/** /**
* Used when user added/removed * Used when user added/removed
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(UserFullInvalidationEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.USER_FULL_INVALIDATION_EVENT)
public class UserFullInvalidationEvent extends InvalidationEvent implements UserCacheInvalidationEvent { public class UserFullInvalidationEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId; @ProtoField(2)
private String username; final String username;
private String email; @ProtoField(3)
private String realmId; final String email;
private boolean identityFederationEnabled; @ProtoField(4)
private Map<String, String> federatedIdentities; final String realmId;
@ProtoField(5)
final boolean identityFederationEnabled;
@ProtoField(value = 6, mapImplementation = HashMap.class)
final Map<String, String> federatedIdentities;
public static UserFullInvalidationEvent create(String userId, String username, String email, String realmId, boolean identityFederationEnabled, Stream<FederatedIdentityModel> federatedIdentities) { private UserFullInvalidationEvent(String id, String username, String email, String realmId, boolean identityFederationEnabled, Map<String, String> federatedIdentities) {
UserFullInvalidationEvent event = new UserFullInvalidationEvent(); super(id);
event.userId = userId; this.username = Objects.requireNonNull(username);
event.username = username; this.email = email;
event.email = email; this.realmId = Objects.requireNonNull(realmId);
event.realmId = realmId; this.federatedIdentities = federatedIdentities;
this.identityFederationEnabled = identityFederationEnabled;
event.identityFederationEnabled = identityFederationEnabled;
if (identityFederationEnabled) {
event.federatedIdentities = federatedIdentities.collect(Collectors.toMap(socialLink -> socialLink.getIdentityProvider(),
socialLink -> socialLink.getUserId()));
}
return event;
} }
@Override public static UserFullInvalidationEvent create(String userId, String username, String email, String realmId, boolean identityFederationEnabled, Stream<FederatedIdentityModel> federatedIdentities) {
public String getId() { Map<String, String> federatedIdentitiesMap = null;
return userId; if (identityFederationEnabled) {
federatedIdentitiesMap = federatedIdentities.collect(Collectors.toMap(FederatedIdentityModel::getIdentityProvider,
FederatedIdentityModel::getUserId));
}
return new UserFullInvalidationEvent(userId, username, email, realmId, identityFederationEnabled, federatedIdentitiesMap);
}
@ProtoFactory
static UserFullInvalidationEvent protoFactory(String id, String username, String email, String realmId, boolean identityFederationEnabled, Map<String, String> federatedIdentities) {
return new UserFullInvalidationEvent(id, username, Marshalling.emptyStringToNull(email), realmId, identityFederationEnabled, federatedIdentities);
} }
public Map<String, String> getFederatedIdentities() { public Map<String, String> getFederatedIdentities() {
@ -77,12 +79,12 @@ public class UserFullInvalidationEvent extends InvalidationEvent implements User
@Override @Override
public String toString() { public String toString() {
return String.format("UserFullInvalidationEvent [ userId=%s, username=%s, email=%s ]", userId, username, email); return String.format("UserFullInvalidationEvent [ userId=%s, username=%s, email=%s ]", getId(), username, email);
} }
@Override @Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) { public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.fullUserInvalidation(userId, username, email, realmId, identityFederationEnabled, federatedIdentities, invalidations); userCache.fullUserInvalidation(getId(), username, email, realmId, identityFederationEnabled, federatedIdentities, invalidations);
} }
@Override @Override
@ -91,50 +93,12 @@ public class UserFullInvalidationEvent extends InvalidationEvent implements User
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
UserFullInvalidationEvent that = (UserFullInvalidationEvent) o; UserFullInvalidationEvent that = (UserFullInvalidationEvent) o;
return identityFederationEnabled == that.identityFederationEnabled && Objects.equals(userId, that.userId) && Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId) && Objects.equals(federatedIdentities, that.federatedIdentities); return identityFederationEnabled == that.identityFederationEnabled && Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId) && Objects.equals(federatedIdentities, that.federatedIdentities);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), userId, username, email, realmId, identityFederationEnabled, federatedIdentities); return Objects.hash(super.hashCode(), username, email, realmId, identityFederationEnabled, federatedIdentities);
} }
public static class ExternalizerImpl implements Externalizer<UserFullInvalidationEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserFullInvalidationEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
MarshallUtil.marshallString(obj.username, output);
MarshallUtil.marshallString(obj.email, output);
MarshallUtil.marshallString(obj.realmId, output);
output.writeBoolean(obj.identityFederationEnabled);
KeycloakMarshallUtil.writeMap(obj.federatedIdentities, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public UserFullInvalidationEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserFullInvalidationEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserFullInvalidationEvent res = new UserFullInvalidationEvent();
res.userId = MarshallUtil.unmarshallString(input);
res.username = MarshallUtil.unmarshallString(input);
res.email = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.identityFederationEnabled = input.readBoolean();
res.federatedIdentities = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, HashMap::new);
return res;
}
}
} }

View file

@ -20,47 +20,49 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager; import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(UserUpdatedEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.USER_UPDATED_EVENT)
public class UserUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent { public class UserUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId; @ProtoField(2)
private String username; final String username;
private String email; @ProtoField(3)
private String realmId; final String email;
@ProtoField(4)
final String realmId;
public static UserUpdatedEvent create(String userId, String username, String email, String realmId) { private UserUpdatedEvent(String id, String username, String email, String realmId) {
UserUpdatedEvent event = new UserUpdatedEvent(); super(id);
event.userId = userId; this.username = Objects.requireNonNull(username);
event.username = username; this.email = email;
event.email = email; this.realmId = Objects.requireNonNull(realmId);
event.realmId = realmId;
return event;
} }
@Override public static UserUpdatedEvent create(String id, String username, String email, String realmId) {
public String getId() { return new UserUpdatedEvent(id, username, email, realmId);
return userId; }
@ProtoFactory
static UserUpdatedEvent protoFactory(String id, String username, String email, String realmId) {
return new UserUpdatedEvent(id, username, Marshalling.emptyStringToNull(email), realmId);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("UserUpdatedEvent [ userId=%s, username=%s, email=%s ]", userId, username, email); return String.format("UserUpdatedEvent [ userId=%s, username=%s, email=%s ]", getId(), username, email);
} }
@Override @Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) { public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.userUpdatedInvalidations(userId, username, email, realmId, invalidations); userCache.userUpdatedInvalidations(getId(), username, email, realmId, invalidations);
} }
@Override @Override
@ -69,46 +71,12 @@ public class UserUpdatedEvent extends InvalidationEvent implements UserCacheInva
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
UserUpdatedEvent that = (UserUpdatedEvent) o; UserUpdatedEvent that = (UserUpdatedEvent) o;
return Objects.equals(userId, that.userId) && Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId); return Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), userId, username, email, realmId); return Objects.hash(super.hashCode(), username, email, realmId);
} }
public static class ExternalizerImpl implements Externalizer<UserUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
MarshallUtil.marshallString(obj.username, output);
MarshallUtil.marshallString(obj.email, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public UserUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserUpdatedEvent res = new UserUpdatedEvent();
res.userId = MarshallUtil.unmarshallString(input);
res.username = MarshallUtil.unmarshallString(input);
res.email = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,24 +1,20 @@
package org.keycloak.models.cache.infinispan.stream; package org.keycloak.models.cache.infinispan.stream;
import org.keycloak.models.cache.infinispan.entities.GroupListQuery;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.entities.GroupListQuery;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@SerializeWith(GroupListPredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.GROUP_LIST_PREDICATE)
public class GroupListPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class GroupListPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String realm; private String realm;
public static GroupListPredicate create() { public static GroupListPredicate create() {
@ -30,43 +26,18 @@ public class GroupListPredicate implements Predicate<Map.Entry<String, Revisione
return this; return this;
} }
@ProtoField(1)
String getRealm() {
return realm;
}
void setRealm(String realm) {
this.realm = realm;
}
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof GroupListQuery groupList && groupList.getRealm().equals(realm);
if (value == null) return false;
if (value instanceof GroupListQuery) {
GroupListQuery groupList = (GroupListQuery)value;
if (groupList.getRealm().equals(realm)) return true;
}
return false;
} }
public static class ExternalizerImpl implements Externalizer<GroupListPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupListPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realm, output);
}
@Override
public GroupListPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupListPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupListPredicate res = new GroupListPredicate();
res.realm = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,28 +1,25 @@
package org.keycloak.models.cache.infinispan.stream; package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.CachedClient; import org.keycloak.models.cache.infinispan.entities.CachedClient;
import org.keycloak.models.cache.infinispan.entities.CachedClientScope; import org.keycloak.models.cache.infinispan.entities.CachedClientScope;
import org.keycloak.models.cache.infinispan.entities.CachedGroup; import org.keycloak.models.cache.infinispan.entities.CachedGroup;
import org.keycloak.models.cache.infinispan.entities.CachedRole; import org.keycloak.models.cache.infinispan.entities.CachedRole;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.models.cache.infinispan.entities.RoleQuery; import org.keycloak.models.cache.infinispan.entities.RoleQuery;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@SerializeWith(HasRolePredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.HAS_ROLE_PREDICATE)
public class HasRolePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class HasRolePredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String role; private String role;
public static HasRolePredicate create() { public static HasRolePredicate create() {
@ -34,61 +31,23 @@ public class HasRolePredicate implements Predicate<Map.Entry<String, Revisioned>
return this; return this;
} }
@ProtoField(1)
String getRole() {
return role;
}
void setRole(String role) {
this.role = role;
}
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); Object value = entry.getValue();
if (value == null) return false; return (value instanceof CachedRole cachedRole && cachedRole.getComposites().contains(role)) ||
if (value instanceof CachedRole) { (value instanceof CachedGroup cachedGroup && cachedGroup.getRoleMappings(null).contains(role)) ||
CachedRole cachedRole = (CachedRole)value; (value instanceof RoleQuery roleQuery && roleQuery.getRoles().contains(role)) ||
if (cachedRole.getComposites().contains(role)) return true; (value instanceof CachedClient cachedClient && cachedClient.getScope().contains(role)) ||
} (value instanceof CachedClientScope cachedClientScope && cachedClientScope.getScope().contains(role));
if (value instanceof CachedGroup) {
CachedGroup cachedRole = (CachedGroup)value;
if (cachedRole.getRoleMappings(null).contains(role)) return true;
}
if (value instanceof RoleQuery) {
RoleQuery roleQuery = (RoleQuery)value;
if (roleQuery.getRoles().contains(role)) return true;
}
if (value instanceof CachedClient) {
CachedClient cachedClient = (CachedClient)value;
if (cachedClient.getScope().contains(role)) return true;
}
if (value instanceof CachedClientScope) {
CachedClientScope cachedClientScope = (CachedClientScope)value;
if (cachedClientScope.getScope().contains(role)) return true;
}
return false;
} }
public static class ExternalizerImpl implements Externalizer<HasRolePredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, HasRolePredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.role, output);
}
@Override
public HasRolePredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public HasRolePredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
HasRolePredicate res = new HasRolePredicate();
res.role = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,24 +1,21 @@
package org.keycloak.models.cache.infinispan.stream; package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.InClient; import org.keycloak.models.cache.infinispan.entities.InClient;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@SerializeWith(InClientPredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.IN_CLIENT_PREDICATE)
public class InClientPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class InClientPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String clientId; private String clientId;
public static InClientPredicate create() { public static InClientPredicate create() {
@ -30,41 +27,18 @@ public class InClientPredicate implements Predicate<Map.Entry<String, Revisioned
return this; return this;
} }
@ProtoField(1)
String getClientId() {
return clientId;
}
void setClientId(String clientId) {
this.clientId = clientId;
}
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof InClient inClient && clientId.equals(inClient.getClientId());
if (value == null) return false;
if (!(value instanceof InClient)) return false;
return clientId.equals(((InClient)value).getClientId());
} }
public static class ExternalizerImpl implements Externalizer<InClientPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InClientPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientId, output);
}
@Override
public InClientPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InClientPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InClientPredicate res = new InClientPredicate();
res.clientId = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -17,21 +17,18 @@
package org.keycloak.models.cache.infinispan.stream; package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.GroupNameQuery; import org.keycloak.models.cache.infinispan.entities.GroupNameQuery;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
@SerializeWith(InGroupPredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.IN_GROUP_PREDICATE)
public class InGroupPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class InGroupPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String group; private String group;
public static InGroupPredicate create() { public static InGroupPredicate create() {
@ -43,41 +40,19 @@ public class InGroupPredicate implements Predicate<Map.Entry<String, Revisioned>
return this; return this;
} }
@ProtoField(1)
String getGroup() {
return group;
}
void setGroup(String group) {
this.group = group;
}
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof GroupNameQuery groupNameQuery && group.equals(groupNameQuery.getGroupId());
if (value == null) return false;
if (!(value instanceof GroupNameQuery)) return false;
return group.equals(((GroupNameQuery)value).getGroupId());
} }
public static class ExternalizerImpl implements Externalizer<InGroupPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InGroupPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.group, output);
}
@Override
public InGroupPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InGroupPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InGroupPredicate res = new InGroupPredicate();
res.group = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,24 +1,20 @@
package org.keycloak.models.cache.infinispan.stream; package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.InIdentityProvider; import org.keycloak.models.cache.infinispan.entities.InIdentityProvider;
import org.keycloak.models.cache.infinispan.entities.InRealm;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
@SerializeWith(InIdentityProviderPredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.IN_IDENTITY_PROVIDER_PREDICATE)
public class InIdentityProviderPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class InIdentityProviderPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String id; private String id;
public static InIdentityProviderPredicate create() { public static InIdentityProviderPredicate create() {
@ -30,41 +26,18 @@ public class InIdentityProviderPredicate implements Predicate<Map.Entry<String,
return this; return this;
} }
@ProtoField(1)
String getId() {
return id;
}
void setId(String id) {
this.id = id;
}
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof InIdentityProvider provider && provider.contains(id);
if (value == null) return false;
if (!(value instanceof InIdentityProvider)) return false;
return ((InIdentityProvider)value).contains(id);
} }
public static class ExternalizerImpl implements Externalizer<InIdentityProviderPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InIdentityProviderPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
}
@Override
public InIdentityProviderPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InIdentityProviderPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InIdentityProviderPredicate res = new InIdentityProviderPredicate();
res.id = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -1,24 +1,21 @@
package org.keycloak.models.cache.infinispan.stream; package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.InRealm; import org.keycloak.models.cache.infinispan.entities.InRealm;
import org.keycloak.models.cache.infinispan.entities.Revisioned; import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@SerializeWith(InRealmPredicate.ExternalizerImpl.class) @ProtoTypeId(Marshalling.IN_REALM_PREDICATE)
public class InRealmPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable { public class InRealmPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String realm; private String realm;
public static InRealmPredicate create() { public static InRealmPredicate create() {
@ -30,41 +27,19 @@ public class InRealmPredicate implements Predicate<Map.Entry<String, Revisioned>
return this; return this;
} }
@ProtoField(1)
String getRealm() {
return realm;
}
void setRealm(String realm) {
this.realm = realm;
}
@Override @Override
public boolean test(Map.Entry<String, Revisioned> entry) { public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue(); return entry.getValue() instanceof InRealm inRealm && realm.equals(inRealm.getRealm());
if (value == null) return false;
if (!(value instanceof InRealm)) return false;
return realm.equals(((InRealm)value).getRealm());
} }
public static class ExternalizerImpl implements Externalizer<InRealmPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InRealmPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realm, output);
}
@Override
public InRealmPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InRealmPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InRealmPredicate res = new InRealmPredicate();
res.realm = MarshallUtil.unmarshallString(input);
return res;
}
}
} }

View file

@ -23,7 +23,6 @@ import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.jboss.logging.Logger;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator; import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
@ -34,7 +33,7 @@ import org.keycloak.models.cache.infinispan.events.AuthenticationSessionAuthNote
import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity; import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent; import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction; import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.stream.RootAuthenticationSessionPredicate; import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator; import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.utils.SessionExpiration; import org.keycloak.models.utils.SessionExpiration;
import org.keycloak.sessions.AuthenticationSessionCompoundId; import org.keycloak.sessions.AuthenticationSessionCompoundId;
@ -120,7 +119,7 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
Iterator<Map.Entry<String, RootAuthenticationSessionEntity>> itr = CacheDecorators.localCache(cache) Iterator<Map.Entry<String, RootAuthenticationSessionEntity>> itr = CacheDecorators.localCache(cache)
.entrySet() .entrySet()
.stream() .stream()
.filter(RootAuthenticationSessionPredicate.create(realmId)) .filter(SessionPredicate.create(realmId))
.iterator(); .iterator();
while (itr.hasNext()) { while (itr.hasNext()) {
@ -149,7 +148,7 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
ClusterProvider cluster = session.getProvider(ClusterProvider.class); ClusterProvider cluster = session.getProvider(ClusterProvider.class);
cluster.notify( cluster.notify(
InfinispanAuthenticationSessionProviderFactory.AUTHENTICATION_SESSION_EVENTS, InfinispanAuthenticationSessionProviderFactory.AUTHENTICATION_SESSION_EVENTS,
AuthenticationSessionAuthNoteUpdateEvent.create(compoundId.getRootSessionId(), compoundId.getTabId(), compoundId.getClientUUID(), authNotesFragment), AuthenticationSessionAuthNoteUpdateEvent.create(compoundId.getRootSessionId(), compoundId.getTabId(), authNotesFragment),
true, true,
ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC
); );

View file

@ -35,7 +35,7 @@ import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailures
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction; import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker; import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.stream.Mappers; import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.UserLoginFailurePredicate; import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper; import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts; import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
@ -125,7 +125,7 @@ public class InfinispanUserLoginFailureProvider implements UserLoginFailureProvi
localCacheStoreIgnore localCacheStoreIgnore
.entrySet() .entrySet()
.stream() .stream()
.filter(UserLoginFailurePredicate.create(realmId)) .filter(SessionWrapperPredicate.create(realmId))
.map(Mappers.loginFailureId()) .map(Mappers.loginFailureId())
.forEach(loginFailureKey -> { .forEach(loginFailureKey -> {
// Remove loginFailure from remoteCache too. Use removeAsync for better perf // Remove loginFailure from remoteCache too. Use removeAsync for better perf

View file

@ -24,12 +24,13 @@ import org.keycloak.Config;
import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakSessionTask; import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserLoginFailureProvider; import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserLoginFailureProviderFactory; import org.keycloak.models.UserLoginFailureProviderFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey; import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
@ -40,15 +41,14 @@ import org.keycloak.models.sessions.infinispan.events.AbstractUserSessionCluster
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent; import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailuresEvent; import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailuresEvent;
import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer; import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer;
import org.keycloak.models.sessions.infinispan.initializer.InitializerState;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker; import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener; import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader; import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts; import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.PostMigrationEvent; import org.keycloak.models.utils.PostMigrationEvent;
import java.io.Serializable;
import java.util.Set; import java.util.Set;
import static org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory.PROVIDER_PRIORITY; import static org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory.PROVIDER_PRIORITY;
@ -195,7 +195,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
@Override @Override
public void run(KeycloakSession session) { public void run(KeycloakSession session) {
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class); InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, Serializable> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); Cache<String, InitializerState> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME);
int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME) int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME)
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000); .getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);

View file

@ -17,53 +17,6 @@
package org.keycloak.models.sessions.infinispan; package org.keycloak.models.sessions.infinispan;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.commons.api.BasicCache;
import org.infinispan.context.Flag;
import org.infinispan.stream.CacheCollectors;
import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.OfflineUserSessionModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.Tasks;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction;
import org.keycloak.models.sessions.infinispan.changes.SessionUpdateTask;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.light.LightweightUserAdapter;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -85,6 +38,55 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.commons.api.BasicCache;
import org.infinispan.commons.util.concurrent.CompletionStages;
import org.infinispan.context.Flag;
import org.infinispan.stream.CacheCollectors;
import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.OfflineUserSessionModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.light.LightweightUserAdapter;
import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.SessionUpdateTask;
import org.keycloak.models.sessions.infinispan.changes.Tasks;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import static org.keycloak.models.Constants.SESSION_NOTE_LIGHTWEIGHT_USER; import static org.keycloak.models.Constants.SESSION_NOTE_LIGHTWEIGHT_USER;
import static org.keycloak.utils.StreamsUtil.paginatedStream; import static org.keycloak.utils.StreamsUtil.paginatedStream;
@ -270,6 +272,16 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
return getUserSession(realm, id, false); return getUserSession(realm, id, false);
} }
@Override
public void migrate(String modelVersion) {
// Changed encoding from JBoss Marshalling to ProtoStream.
// Unable to read the cached data.
if ("26.0.0".equals(modelVersion)) {
log.debug("Clear caches to migrate to Infinispan Protostream");
CompletionStages.join(session.getProvider(InfinispanConnectionProvider.class).migrateToProtostream());
}
}
protected UserSessionAdapter getUserSession(RealmModel realm, String id, boolean offline) { protected UserSessionAdapter getUserSession(RealmModel realm, String id, boolean offline) {
UserSessionEntity userSessionEntityFromCache = getUserSessionEntity(realm, id, offline); UserSessionEntity userSessionEntityFromCache = getUserSessionEntity(realm, id, offline);
@ -660,7 +672,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
localCacheStoreIgnore localCacheStoreIgnore
.entrySet() .entrySet()
.stream() .stream()
.filter(SessionPredicate.create(realmId)) .filter(SessionWrapperPredicate.create(realmId))
.map(Mappers.userSessionEntity()) .map(Mappers.userSessionEntity())
.forEach(new Consumer<UserSessionEntity>() { .forEach(new Consumer<UserSessionEntity>() {

View file

@ -17,6 +17,14 @@
package org.keycloak.models.sessions.infinispan; package org.keycloak.models.sessions.infinispan;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.persistence.remote.RemoteStore; import org.infinispan.persistence.remote.RemoteStore;
@ -27,6 +35,7 @@ import org.keycloak.common.Profile;
import org.keycloak.common.util.Environment; import org.keycloak.common.util.Environment;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
@ -35,15 +44,14 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionProvider; import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.UserSessionProviderFactory; import org.keycloak.models.UserSessionProviderFactory;
import org.keycloak.models.sessions.infinispan.changes.PersistentSessionsWorker;
import org.keycloak.models.sessions.infinispan.changes.PersistentUpdate; import org.keycloak.models.sessions.infinispan.changes.PersistentUpdate;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey; import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.PersistentSessionsWorker; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore; import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStoreFactory; import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStoreFactory;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore; import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStoreFactory; import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStoreFactory;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity; import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity; import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity; import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
@ -51,10 +59,11 @@ import org.keycloak.models.sessions.infinispan.events.AbstractUserSessionCluster
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent; import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent; import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer; import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer;
import org.keycloak.models.sessions.infinispan.initializer.InitializerState;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener; import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader; import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator; import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts; import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.PostMigrationEvent; import org.keycloak.models.utils.PostMigrationEvent;
@ -65,15 +74,6 @@ import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener; import org.keycloak.provider.ProviderEventListener;
import org.keycloak.provider.ServerInfoAwareProviderFactory; import org.keycloak.provider.ServerInfoAwareProviderFactory;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import static org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory.PROVIDER_PRIORITY; import static org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory.PROVIDER_PRIORITY;
public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory, ServerInfoAwareProviderFactory { public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory, ServerInfoAwareProviderFactory {
@ -398,7 +398,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
@Override @Override
public void run(KeycloakSession session) { public void run(KeycloakSession session) {
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class); InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, Serializable> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); Cache<String, InitializerState> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME);
int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME) int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME)
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000); .getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);

View file

@ -17,12 +17,31 @@
package org.keycloak.models.sessions.infinispan; package org.keycloak.models.sessions.infinispan;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Flowable;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException; import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.commons.api.BasicCache; import org.infinispan.commons.api.BasicCache;
import org.infinispan.commons.util.ByRef; import org.infinispan.commons.util.ByRef;
import org.infinispan.commons.util.concurrent.CompletionStages;
import org.infinispan.context.Flag; import org.infinispan.context.Flag;
import org.infinispan.factories.ComponentRegistry; import org.infinispan.factories.ComponentRegistry;
import org.infinispan.persistence.manager.PersistenceManager; import org.infinispan.persistence.manager.PersistenceManager;
@ -32,8 +51,8 @@ import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature; import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Retry; import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil; import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.migration.ModelVersion;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -67,7 +86,7 @@ import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction; import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker; import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.stream.Mappers; import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate; import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate; import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper; import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator; import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
@ -75,24 +94,6 @@ import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.UserModelDelegate; import org.keycloak.models.utils.UserModelDelegate;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.keycloak.models.Constants.SESSION_NOTE_LIGHTWEIGHT_USER; import static org.keycloak.models.Constants.SESSION_NOTE_LIGHTWEIGHT_USER;
import static org.keycloak.utils.StreamsUtil.paginatedStream; import static org.keycloak.utils.StreamsUtil.paginatedStream;
@ -559,7 +560,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
sessions sessions
.entrySet() .entrySet()
.stream() .stream()
.filter(SessionPredicate.create(realmId)) .filter(SessionWrapperPredicate.create(realmId))
.map(Mappers.userSessionEntity()) .map(Mappers.userSessionEntity())
.forEach((Consumer<UserSessionEntity>) userSessionEntity -> { .forEach((Consumer<UserSessionEntity>) userSessionEntity -> {
userSessionsSize.incrementAndGet(); userSessionsSize.incrementAndGet();
@ -586,7 +587,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
sessions sessions
.entrySet() .entrySet()
.stream() .stream()
.filter(SessionPredicate.create(realmId)) .filter(UserSessionPredicate.create(realmId))
.map(Mappers.userSessionEntity()) .map(Mappers.userSessionEntity())
.forEach((Consumer<UserSessionEntity>) userSessionEntity -> { .forEach((Consumer<UserSessionEntity>) userSessionEntity -> {
userSessionsSize.incrementAndGet(); userSessionsSize.incrementAndGet();
@ -1013,8 +1014,11 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
@Override @Override
public void migrate(String modelVersion) { public void migrate(String modelVersion) {
if (new ModelVersion(modelVersion).equals(new ModelVersion("25.0.0"))) { // Changed encoding from JBoss Marshalling to ProtoStream.
migrateNonPersistentSessionsToPersistentSessions(); // Unable to read the cached data.
if ("26.0.0".equals(modelVersion)) {
log.debug("Clear caches to migrate to Infinispan Protostream");
CompletionStages.join(session.getProvider(InfinispanConnectionProvider.class).migrateToProtostream());
} }
} }

View file

@ -10,6 +10,9 @@ import java.util.function.BiFunction;
import org.infinispan.commons.marshall.AdvancedExternalizer; import org.infinispan.commons.marshall.AdvancedExternalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling; import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity; import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
@ -19,13 +22,13 @@ import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
* @param <K> The Infinispan key type. * @param <K> The Infinispan key type.
* @param <T> The Infinispan value type (Keycloak entity) * @param <T> The Infinispan value type (Keycloak entity)
*/ */
@ProtoTypeId(Marshalling.REPLACE_FUNCTION)
public class ReplaceFunction<K, T extends SessionEntity> implements BiFunction<K, SessionEntityWrapper<T>, SessionEntityWrapper<T>> { public class ReplaceFunction<K, T extends SessionEntity> implements BiFunction<K, SessionEntityWrapper<T>, SessionEntityWrapper<T>> {
@SuppressWarnings({"removal", "rawtypes"})
public static final AdvancedExternalizer<ReplaceFunction> INSTANCE = new Externalizer();
private final UUID expectedVersion; private final UUID expectedVersion;
private final SessionEntityWrapper<T> newValue; private final SessionEntityWrapper<T> newValue;
@ProtoFactory
public ReplaceFunction(UUID expectedVersion, SessionEntityWrapper<T> newValue) { public ReplaceFunction(UUID expectedVersion, SessionEntityWrapper<T> newValue) {
this.expectedVersion = Objects.requireNonNull(expectedVersion); this.expectedVersion = Objects.requireNonNull(expectedVersion);
this.newValue = Objects.requireNonNull(newValue); this.newValue = Objects.requireNonNull(newValue);
@ -37,37 +40,13 @@ public class ReplaceFunction<K, T extends SessionEntity> implements BiFunction<K
return expectedVersion.equals(currentValue.getVersion()) ? newValue : currentValue; return expectedVersion.equals(currentValue.getVersion()) ? newValue : currentValue;
} }
@SuppressWarnings({"removal", "rawtypes"}) @ProtoField(1)
private static class Externalizer implements AdvancedExternalizer<ReplaceFunction> { UUID getExpectedVersion() {
return expectedVersion;
}
private static final SessionEntityWrapper.ExternalizerImpl EXTERNALIZER = new SessionEntityWrapper.ExternalizerImpl(); @ProtoField(2)
private static final byte VERSION_1 = 1; SessionEntityWrapper<T> getNewValue() {
return newValue;
@Override
public Set<Class<? extends ReplaceFunction>> getTypeClasses() {
return Set.of(ReplaceFunction.class);
}
@Override
public Integer getId() {
return Marshalling.REPLACE_FUNCTION_ID;
}
@Override
public void writeObject(ObjectOutput output, ReplaceFunction object) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallUUID(object.expectedVersion, output, false);
EXTERNALIZER.writeObject(output, object.newValue);
}
@Override
public ReplaceFunction<?,?> readObject(ObjectInput input) throws IOException, ClassNotFoundException {
var version = input.readByte();
if (version != VERSION_1) {
throw new IOException("Invalid version: " + version);
}
//noinspection unchecked
return new ReplaceFunction<Object, SessionEntity>(MarshallUtil.unmarshallUUID(input, false), EXTERNALIZER.readObject(input));
}
} }
} }

View file

@ -17,32 +17,27 @@
package org.keycloak.models.sessions.infinispan.changes; package org.keycloak.models.sessions.infinispan.changes;
import java.io.IOException; import org.infinispan.protostream.WrappedMessage;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoFactory;
import java.io.ObjectOutput; import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import java.util.HashMap;
import org.jboss.logging.Logger;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(SessionEntityWrapper.ExternalizerImpl.class) @ProtoTypeId(Marshalling.SESSION_ENTITY_WRAPPER)
public class SessionEntityWrapper<S extends SessionEntity> { public class SessionEntityWrapper<S extends SessionEntity> {
private static final Logger log = Logger.getLogger(SessionEntityWrapper.class);
private final UUID version; private final UUID version;
private final S entity; private final S entity;
private final Map<String, String> localMetadata; private final Map<String, String> localMetadata;
@ -87,6 +82,7 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return this.version == null; return this.version == null;
} }
@ProtoField(1)
public UUID getVersion() { public UUID getVersion() {
return version; return version;
} }
@ -95,6 +91,26 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return entity; return entity;
} }
@ProtoField(2)
WrappedMessage getEntityPS() {
return new WrappedMessage(getEntity());
}
@ProtoField(value = 3, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getLocalMetadata() {
return localMetadata;
}
@ProtoFactory
static <T extends SessionEntity> SessionEntityWrapper<T> create(UUID version, WrappedMessage entityPS, Map<String, String> localMetadata) {
assert entityPS != null;
T entity = (T) entityPS.getValue();
if (version == null) {
return new SessionEntityWrapper<>(entity);
}
return new SessionEntityWrapper<>(version, localMetadata, entity);
}
public ClientModel getClientIfNeeded(RealmModel realm) { public ClientModel getClientIfNeeded(RealmModel realm) {
if (entity instanceof AuthenticatedClientSessionEntity) { if (entity instanceof AuthenticatedClientSessionEntity) {
String clientId = ((AuthenticatedClientSessionEntity) entity).getClientId(); String clientId = ((AuthenticatedClientSessionEntity) entity).getClientId();
@ -124,24 +140,19 @@ public class SessionEntityWrapper<S extends SessionEntity> {
localMetadata.put(key, String.valueOf(value)); localMetadata.put(key, String.valueOf(value));
} }
public Map<String, String> getLocalMetadata() {
return localMetadata;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (!(o instanceof SessionEntityWrapper)) return false; return true;
}
SessionEntityWrapper that = (SessionEntityWrapper) o; if (!(o instanceof SessionEntityWrapper)) {
if (!Objects.equals(version, that.version)) {
return false; return false;
} }
return Objects.equals(entity, that.entity); SessionEntityWrapper<?> that = (SessionEntityWrapper<?>) o;
}
return Objects.equals(version, that.version) && Objects.equals(entity, that.entity);
}
@Override @Override
public int hashCode() { public int hashCode() {
@ -154,53 +165,4 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return "SessionEntityWrapper{" + "version=" + version + ", entity=" + entity + ", localMetadata=" + localMetadata + '}'; return "SessionEntityWrapper{" + "version=" + version + ", entity=" + entity + ", localMetadata=" + localMetadata + '}';
} }
public static class ExternalizerImpl implements Externalizer<SessionEntityWrapper> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, SessionEntityWrapper obj) throws IOException {
output.writeByte(VERSION_1);
final boolean forTransport = obj.isForTransport();
output.writeBoolean(forTransport);
if (! forTransport) {
output.writeLong(obj.getVersion().getMostSignificantBits());
output.writeLong(obj.getVersion().getLeastSignificantBits());
MarshallUtil.marshallMap(obj.localMetadata, output);
}
output.writeObject(obj.entity);
}
@Override
public SessionEntityWrapper readObject(ObjectInput input) throws IOException, ClassNotFoundException {
byte version = input.readByte();
if (version != VERSION_1) {
throw new IOException("Invalid version: " + version);
}
final boolean forTransport = input.readBoolean();
if (forTransport) {
final SessionEntity entity = (SessionEntity) input.readObject();
final SessionEntityWrapper res = new SessionEntityWrapper(entity);
if (log.isTraceEnabled()) {
log.tracef("Loaded entity from remote store: %s, version=%s, metadata=%s", entity, res.version, res.localMetadata);
}
return res;
} else {
UUID sessionVersion = new UUID(input.readLong(), input.readLong());
HashMap<String, String> map = MarshallUtil.<String, String, HashMap<String, String>>unmarshallMap(input, HashMap::new);
final SessionEntity entity = (SessionEntity) input.readObject();
if (log.isTraceEnabled()) {
log.tracef("Found entity locally: entity=%s, version=%s, metadata=%s", entity, sessionVersion, map);
}
return new SessionEntityWrapper(sessionVersion, map, entity);
}
}
}
} }

View file

@ -66,8 +66,8 @@ public class CrossDCLastSessionRefreshListener implements ClusterListener {
lastSessionRefreshes.entrySet().stream().forEach((entry) -> { lastSessionRefreshes.entrySet().stream().forEach((entry) -> {
String sessionId = entry.getKey(); String sessionId = entry.getKey();
String realmId = entry.getValue().getRealmId(); String realmId = entry.getValue().realmId();
int lastSessionRefresh = entry.getValue().getLastSessionRefresh(); int lastSessionRefresh = entry.getValue().lastSessionRefresh();
// All nodes will receive the message. So ensure that each node updates just lastSessionRefreshes owned by him. // All nodes will receive the message. So ensure that each node updates just lastSessionRefreshes owned by him.
if (shouldUpdateLocalCache(sessionId)) { if (shouldUpdateLocalCache(sessionId)) {

View file

@ -17,30 +17,29 @@
package org.keycloak.models.sessions.infinispan.changes.sessions; package org.keycloak.models.sessions.infinispan.changes.sessions;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoFactory;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoField;
import java.io.ObjectOutput; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.marshalling.Marshalling;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.cluster.ClusterEvent;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(LastSessionRefreshEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.LAST_SESSION_REFRESH_EVENT)
public class LastSessionRefreshEvent implements ClusterEvent { public class LastSessionRefreshEvent implements ClusterEvent {
private final Map<String, SessionData> lastSessionRefreshes; private final Map<String, SessionData> lastSessionRefreshes;
@ProtoFactory
public LastSessionRefreshEvent(Map<String, SessionData> lastSessionRefreshes) { public LastSessionRefreshEvent(Map<String, SessionData> lastSessionRefreshes) {
this.lastSessionRefreshes = lastSessionRefreshes; this.lastSessionRefreshes = lastSessionRefreshes;
} }
@ProtoField(value = 1, mapImplementation = HashMap.class)
public Map<String, SessionData> getLastSessionRefreshes() { public Map<String, SessionData> getLastSessionRefreshes() {
return lastSessionRefreshes; return lastSessionRefreshes;
} }
@ -55,29 +54,4 @@ public class LastSessionRefreshEvent implements ClusterEvent {
return 1; return 1;
} }
public static class ExternalizerImpl implements Externalizer<LastSessionRefreshEvent> {
@Override
public void writeObject(ObjectOutput output, LastSessionRefreshEvent obj) throws IOException {
MarshallUtil.marshallMap(obj.lastSessionRefreshes, output);
}
@Override
public LastSessionRefreshEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
Map<String, SessionData> map = MarshallUtil.unmarshallMap(input, new MarshallUtil.MapBuilder<String, SessionData, Map<String, SessionData>>() {
@Override
public Map<String, SessionData> build(int size) {
return new HashMap<>(size);
}
});
LastSessionRefreshEvent event = new LastSessionRefreshEvent(map);
return event;
}
}
} }

View file

@ -51,7 +51,7 @@ public class PersisterLastSessionRefreshStore extends AbstractLastSessionRefresh
protected void sendMessage(KeycloakSession kcSession, Map<String, SessionData> refreshesToSend) { protected void sendMessage(KeycloakSession kcSession, Map<String, SessionData> refreshesToSend) {
Map<String, Set<String>> sessionIdsByRealm = Map<String, Set<String>> sessionIdsByRealm =
refreshesToSend.entrySet().stream().collect( refreshesToSend.entrySet().stream().collect(
Collectors.groupingBy(entry -> entry.getValue().getRealmId(), Collectors.groupingBy(entry -> entry.getValue().realmId(),
Collectors.mapping(Map.Entry::getKey, Collectors.toSet()))); Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));
// Update DB with a bit lower value than current time to ensure 'revokeRefreshToken' will work correctly taking server // Update DB with a bit lower value than current time to ensure 'revokeRefreshToken' will work correctly taking server

View file

@ -17,59 +17,17 @@
package org.keycloak.models.sessions.infinispan.changes.sessions; package org.keycloak.models.sessions.infinispan.changes.sessions;
import java.io.IOException; import org.infinispan.protostream.annotations.Proto;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoFactory;
import java.io.ObjectOutput; import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.infinispan.commons.marshall.Externalizer; import org.keycloak.marshalling.Marshalling;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(SessionData.ExternalizerImpl.class) @ProtoTypeId(Marshalling.SESSION_DATA)
public class SessionData { @Proto
public record SessionData(String realmId, int lastSessionRefresh) {
private final String realmId;
private final int lastSessionRefresh;
public SessionData(String realmId, int lastSessionRefresh) {
this.realmId = realmId;
this.lastSessionRefresh = lastSessionRefresh;
}
public String getRealmId() {
return realmId;
}
public int getLastSessionRefresh() {
return lastSessionRefresh;
}
@Override
public String toString() {
return String.format("realmId: %s, lastSessionRefresh: %d", realmId, lastSessionRefresh);
}
public static class ExternalizerImpl implements Externalizer<SessionData> {
@Override
public void writeObject(ObjectOutput output, SessionData obj) throws IOException {
MarshallUtil.marshallString(obj.realmId, output);
KeycloakMarshallUtil.marshall(obj.lastSessionRefresh, output);
}
@Override
public SessionData readObject(ObjectInput input) throws IOException, ClassNotFoundException {
String realmId = MarshallUtil.unmarshallString(input);
int lastSessionRefresh = KeycloakMarshallUtil.unmarshallInteger(input);
return new SessionData(realmId, lastSessionRefresh);
}
}
} }

View file

@ -17,26 +17,24 @@
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoFactory;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoField;
import java.io.ObjectOutput; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(AuthenticatedClientSessionEntity.ExternalizerImpl.class) @ProtoTypeId(Marshalling.AUTHENTICATED_CLIENT_SESSION_ENTITY)
public class AuthenticatedClientSessionEntity extends SessionEntity { public class AuthenticatedClientSessionEntity extends SessionEntity {
public static final Logger logger = Logger.getLogger(AuthenticatedClientSessionEntity.class); public static final Logger logger = Logger.getLogger(AuthenticatedClientSessionEntity.class);
@ -60,6 +58,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.id = id; this.id = id;
} }
@ProtoField(2)
public String getAuthMethod() { public String getAuthMethod() {
return authMethod; return authMethod;
} }
@ -68,6 +67,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.authMethod = authMethod; this.authMethod = authMethod;
} }
@ProtoField(3)
public String getRedirectUri() { public String getRedirectUri() {
return redirectUri; return redirectUri;
} }
@ -76,6 +76,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.redirectUri = redirectUri; this.redirectUri = redirectUri;
} }
@ProtoField(4)
public int getTimestamp() { public int getTimestamp() {
return timestamp; return timestamp;
} }
@ -106,6 +107,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
getNotes().put(CLIENT_ID_NOTE, clientId); getNotes().put(CLIENT_ID_NOTE, clientId);
} }
@ProtoField(value = 5)
public String getAction() { public String getAction() {
return action; return action;
} }
@ -114,6 +116,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.action = action; this.action = action;
} }
@ProtoField(value = 6, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getNotes() { public Map<String, String> getNotes() {
return notes; return notes;
} }
@ -122,6 +125,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.notes = notes; this.notes = notes;
} }
@ProtoField(7)
public UUID getId() { public UUID getId() {
return id; return id;
} }
@ -133,14 +137,26 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (!(o instanceof AuthenticatedClientSessionEntity)) return false; return true;
}
if (!(o instanceof AuthenticatedClientSessionEntity that)) {
return false;
}
AuthenticatedClientSessionEntity that = (AuthenticatedClientSessionEntity) o; return Objects.equals(id, that.id);
}
if (id != null ? !id.equals(that.id) : that.id != null) return false; // factory method required because of final fields
@ProtoFactory
return true; AuthenticatedClientSessionEntity(String realmId, String authMethod, String redirectUri, int timestamp, String action, Map<String, String> notes, UUID id) {
super(realmId);
this.authMethod = authMethod;
this.redirectUri = redirectUri;
this.timestamp = timestamp;
this.action = action;
this.notes = notes;
this.id = id;
} }
@Override @Override
@ -180,42 +196,4 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
public void setUserSessionId(String userSessionId) { public void setUserSessionId(String userSessionId) {
this.userSessionId = userSessionId; this.userSessionId = userSessionId;
} }
public static class ExternalizerImpl implements Externalizer<AuthenticatedClientSessionEntity> {
@Override
public void writeObject(ObjectOutput output, AuthenticatedClientSessionEntity session) throws IOException {
MarshallUtil.marshallUUID(session.id, output, false);
MarshallUtil.marshallString(session.getRealmId(), output);
MarshallUtil.marshallString(session.getAuthMethod(), output);
MarshallUtil.marshallString(session.getRedirectUri(), output);
KeycloakMarshallUtil.marshall(session.getTimestamp(), output);
MarshallUtil.marshallString(session.getAction(), output);
Map<String, String> notes = session.getNotes();
KeycloakMarshallUtil.writeMap(notes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public AuthenticatedClientSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
AuthenticatedClientSessionEntity sessionEntity = new AuthenticatedClientSessionEntity(MarshallUtil.unmarshallUUID(input, false));
sessionEntity.setRealmId(MarshallUtil.unmarshallString(input));
sessionEntity.setAuthMethod(MarshallUtil.unmarshallString(input));
sessionEntity.setRedirectUri(MarshallUtil.unmarshallString(input));
sessionEntity.setTimestamp(KeycloakMarshallUtil.unmarshallInteger(input));
sessionEntity.setAction(MarshallUtil.unmarshallString(input));
Map<String, String> notes = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT,
new KeycloakMarshallUtil.ConcurrentHashMapBuilder<>());
sessionEntity.setNotes(notes);
return sessionEntity;
}
}
} }

View file

@ -16,34 +16,35 @@
*/ */
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoField;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectOutput; import org.keycloak.marshalling.Marshalling;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* *
* @author hmlnarik * @author hmlnarik
*/ */
@SerializeWith(AuthenticatedClientSessionStore.ExternalizerImpl.class) @ProtoTypeId(Marshalling.AUTHENTICATED_CLIENT_SESSION_STORE)
public class AuthenticatedClientSessionStore { public class AuthenticatedClientSessionStore {
/** /**
* Maps client UUID to client session ID. * Maps client UUID to client session ID.
*/ */
private final ConcurrentHashMap<String, UUID> authenticatedClientSessionIds; private final ConcurrentMap<String, UUID> authenticatedClientSessionIds;
public AuthenticatedClientSessionStore() { public AuthenticatedClientSessionStore() {
authenticatedClientSessionIds = new ConcurrentHashMap<>(); authenticatedClientSessionIds = new ConcurrentHashMap<>();
} }
private AuthenticatedClientSessionStore(ConcurrentHashMap<String, UUID> authenticatedClientSessionIds) { @ProtoFactory
AuthenticatedClientSessionStore(ConcurrentMap<String, UUID> authenticatedClientSessionIds) {
this.authenticatedClientSessionIds = authenticatedClientSessionIds; this.authenticatedClientSessionIds = authenticatedClientSessionIds;
} }
@ -79,37 +80,14 @@ public class AuthenticatedClientSessionStore {
return authenticatedClientSessionIds.size(); return authenticatedClientSessionIds.size();
} }
@ProtoField(value = 1, mapImplementation = ConcurrentHashMap.class)
ConcurrentMap<String, UUID> getAuthenticatedClientSessionIds() {
return authenticatedClientSessionIds;
}
@Override @Override
public String toString() { public String toString() {
return this.authenticatedClientSessionIds.toString(); return this.authenticatedClientSessionIds.toString();
} }
public static class ExternalizerImpl implements Externalizer<AuthenticatedClientSessionStore> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, AuthenticatedClientSessionStore obj) throws IOException {
output.writeByte(VERSION_1);
KeycloakMarshallUtil.writeMap(obj.authenticatedClientSessionIds, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.UUID_EXT, output);
}
@Override
public AuthenticatedClientSessionStore readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public AuthenticatedClientSessionStore readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
AuthenticatedClientSessionStore res = new AuthenticatedClientSessionStore(
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.UUID_EXT, ConcurrentHashMap::new)
);
return res;
}
}
} }

View file

@ -17,17 +17,12 @@
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import org.infinispan.commons.marshall.Externalizer; import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.infinispan.commons.marshall.SerializeWith; import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.sessions.CommonClientSessionModel.ExecutionStatus;
import java.io.IOException; import java.util.HashSet;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -35,8 +30,8 @@ import java.util.concurrent.ConcurrentHashMap;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(AuthenticationSessionEntity.ExternalizerImpl.class) @ProtoTypeId(Marshalling.AUTHENTICATION_SESSION_ENTITY)
public class AuthenticationSessionEntity implements Serializable { public class AuthenticationSessionEntity {
private String clientUUID; private String clientUUID;
@ -60,12 +55,12 @@ public class AuthenticationSessionEntity implements Serializable {
} }
public AuthenticationSessionEntity( public AuthenticationSessionEntity(
String clientUUID, String clientUUID,
String authUserId, String authUserId,
int timestamp, int timestamp,
String redirectUri, String action, Set<String> clientScopes, String redirectUri, String action, Set<String> clientScopes,
Map<String, AuthenticationSessionModel.ExecutionStatus> executionStatus, String protocol, Map<String, AuthenticationSessionModel.ExecutionStatus> executionStatus, String protocol,
Map<String, String> clientNotes, Map<String, String> authNotes, Set<String> requiredActions, Map<String, String> userSessionNotes) { Map<String, String> clientNotes, Map<String, String> authNotes, Set<String> requiredActions, Map<String, String> userSessionNotes) {
this(clientUUID, authUserId, redirectUri, action, clientScopes, executionStatus, protocol, clientNotes, authNotes, requiredActions, userSessionNotes); this(clientUUID, authUserId, redirectUri, action, clientScopes, executionStatus, protocol, clientNotes, authNotes, requiredActions, userSessionNotes);
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@ -93,6 +88,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.userSessionNotes = userSessionNotes; this.userSessionNotes = userSessionNotes;
} }
@ProtoField(1)
public String getClientUUID() { public String getClientUUID() {
return clientUUID; return clientUUID;
} }
@ -101,6 +97,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.clientUUID = clientUUID; this.clientUUID = clientUUID;
} }
@ProtoField(2)
public String getAuthUserId() { public String getAuthUserId() {
return authUserId; return authUserId;
} }
@ -109,6 +106,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.authUserId = authUserId; this.authUserId = authUserId;
} }
@ProtoField(3)
public int getTimestamp() { public int getTimestamp() {
return timestamp; return timestamp;
} }
@ -117,6 +115,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@ProtoField(4)
public String getRedirectUri() { public String getRedirectUri() {
return redirectUri; return redirectUri;
} }
@ -125,6 +124,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.redirectUri = redirectUri; this.redirectUri = redirectUri;
} }
@ProtoField(5)
public String getAction() { public String getAction() {
return action; return action;
} }
@ -133,6 +133,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.action = action; this.action = action;
} }
@ProtoField(value = 6, collectionImplementation = HashSet.class)
public Set<String> getClientScopes() { public Set<String> getClientScopes() {
return clientScopes; return clientScopes;
} }
@ -141,6 +142,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.clientScopes = clientScopes; this.clientScopes = clientScopes;
} }
@ProtoField(value = 7, mapImplementation = ConcurrentHashMap.class)
public Map<String, AuthenticationSessionModel.ExecutionStatus> getExecutionStatus() { public Map<String, AuthenticationSessionModel.ExecutionStatus> getExecutionStatus() {
return executionStatus; return executionStatus;
} }
@ -149,6 +151,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.executionStatus = executionStatus; this.executionStatus = executionStatus;
} }
@ProtoField(8)
public String getProtocol() { public String getProtocol() {
return protocol; return protocol;
} }
@ -157,6 +160,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.protocol = protocol; this.protocol = protocol;
} }
@ProtoField(value = 9, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getClientNotes() { public Map<String, String> getClientNotes() {
return clientNotes; return clientNotes;
} }
@ -165,6 +169,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.clientNotes = clientNotes; this.clientNotes = clientNotes;
} }
@ProtoField(value = 10, collectionImplementation = HashSet.class)
public Set<String> getRequiredActions() { public Set<String> getRequiredActions() {
return requiredActions; return requiredActions;
} }
@ -173,6 +178,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.requiredActions = requiredActions; this.requiredActions = requiredActions;
} }
@ProtoField(value = 11, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getUserSessionNotes() { public Map<String, String> getUserSessionNotes() {
return userSessionNotes; return userSessionNotes;
} }
@ -181,6 +187,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.userSessionNotes = userSessionNotes; this.userSessionNotes = userSessionNotes;
} }
@ProtoField(value = 12, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getAuthNotes() { public Map<String, String> getAuthNotes() {
return authNotes; return authNotes;
} }
@ -188,109 +195,4 @@ public class AuthenticationSessionEntity implements Serializable {
public void setAuthNotes(Map<String, String> authNotes) { public void setAuthNotes(Map<String, String> authNotes) {
this.authNotes = authNotes; this.authNotes = authNotes;
} }
public static class ExternalizerImpl implements Externalizer<AuthenticationSessionEntity> {
private static final int VERSION_1 = 1;
private static final int VERSION_2 = 2;
public static final ExternalizerImpl INSTANCE = new ExternalizerImpl();
private static AuthenticationSessionModel.ExecutionStatus fromOrdinal(int ordinal) {
ExecutionStatus[] values = AuthenticationSessionModel.ExecutionStatus.values();
return (ordinal < 0 || ordinal >= values.length)
? null
: values[ordinal];
}
public static final Externalizer<AuthenticationSessionModel.ExecutionStatus> EXECUTION_STATUS_EXT = new Externalizer<AuthenticationSessionModel.ExecutionStatus>() {
@Override
public void writeObject(ObjectOutput output, AuthenticationSessionModel.ExecutionStatus e) throws IOException {
MarshallUtil.marshallEnum(e, output);
}
@Override
public AuthenticationSessionModel.ExecutionStatus readObject(ObjectInput input) throws IOException, ClassNotFoundException {
return MarshallUtil.unmarshallEnum(input, ExternalizerImpl::fromOrdinal);
}
};
@Override
public void writeObject(ObjectOutput output, AuthenticationSessionEntity value) throws IOException {
output.writeByte(VERSION_2);
MarshallUtil.marshallString(value.clientUUID, output);
MarshallUtil.marshallString(value.authUserId, output);
output.writeInt(value.timestamp);
MarshallUtil.marshallString(value.redirectUri, output);
MarshallUtil.marshallString(value.action, output);
KeycloakMarshallUtil.writeCollection(value.clientScopes, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeMap(value.executionStatus, KeycloakMarshallUtil.STRING_EXT, EXECUTION_STATUS_EXT, output);
MarshallUtil.marshallString(value.protocol, output);
KeycloakMarshallUtil.writeMap(value.clientNotes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeMap(value.authNotes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(value.requiredActions, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeMap(value.userSessionNotes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public AuthenticationSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
case VERSION_2:
return readObjectVersion2(input);
default:
throw new IOException("Unknown version");
}
}
public AuthenticationSessionEntity readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return new AuthenticationSessionEntity(
MarshallUtil.unmarshallString(input), // clientUUID
MarshallUtil.unmarshallString(input), // authUserId
MarshallUtil.unmarshallString(input), // redirectUri
MarshallUtil.unmarshallString(input), // action
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // clientScopes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, EXECUTION_STATUS_EXT, size -> new ConcurrentHashMap<>(size)), // executionStatus
MarshallUtil.unmarshallString(input), // protocol
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // clientNotes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // authNotes
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // requiredActions
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)) // userSessionNotes
);
}
public AuthenticationSessionEntity readObjectVersion2(ObjectInput input) throws IOException, ClassNotFoundException {
return new AuthenticationSessionEntity(
MarshallUtil.unmarshallString(input), // clientUUID
MarshallUtil.unmarshallString(input), // authUserId
input.readInt(), // timestamp
MarshallUtil.unmarshallString(input), // redirectUri
MarshallUtil.unmarshallString(input), // action
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // clientScopes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, EXECUTION_STATUS_EXT, size -> new ConcurrentHashMap<>(size)), // executionStatus
MarshallUtil.unmarshallString(input), // protocol
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // clientNotes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // authNotes
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // requiredActions
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)) // userSessionNotes
);
}
}
} }

View file

@ -17,17 +17,16 @@
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoField;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectOutput; import org.keycloak.marshalling.Marshalling;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import java.util.Objects;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@SerializeWith(LoginFailureEntity.ExternalizerImpl.class) @ProtoTypeId(Marshalling.LOGIN_FAILURE_ENTITY)
public class LoginFailureEntity extends SessionEntity { public class LoginFailureEntity extends SessionEntity {
private String userId; private String userId;
@ -51,6 +50,7 @@ public class LoginFailureEntity extends SessionEntity {
this.lastIPFailure = lastIPFailure; this.lastIPFailure = lastIPFailure;
} }
@ProtoField(2)
public String getUserId() { public String getUserId() {
return userId; return userId;
} }
@ -59,6 +59,7 @@ public class LoginFailureEntity extends SessionEntity {
this.userId = userId; this.userId = userId;
} }
@ProtoField(3)
public int getFailedLoginNotBefore() { public int getFailedLoginNotBefore() {
return failedLoginNotBefore; return failedLoginNotBefore;
} }
@ -69,6 +70,7 @@ public class LoginFailureEntity extends SessionEntity {
} }
} }
@ProtoField(4)
public int getNumFailures() { public int getNumFailures() {
return numFailures; return numFailures;
} }
@ -77,6 +79,7 @@ public class LoginFailureEntity extends SessionEntity {
this.numFailures = numFailures; this.numFailures = numFailures;
} }
@ProtoField(5)
public int getNumTemporaryLockouts() { public int getNumTemporaryLockouts() {
return numTemporaryLockouts; return numTemporaryLockouts;
} }
@ -85,6 +88,7 @@ public class LoginFailureEntity extends SessionEntity {
this.numTemporaryLockouts = numTemporaryLockouts; this.numTemporaryLockouts = numTemporaryLockouts;
} }
@ProtoField(6)
public long getLastFailure() { public long getLastFailure() {
return lastFailure; return lastFailure;
} }
@ -95,6 +99,7 @@ public class LoginFailureEntity extends SessionEntity {
} }
} }
@ProtoField(7)
public String getLastIPFailure() { public String getLastIPFailure() {
return lastIPFailure; return lastIPFailure;
} }
@ -113,16 +118,17 @@ public class LoginFailureEntity extends SessionEntity {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (!(o instanceof LoginFailureEntity)) return false; return true;
}
if (!(o instanceof LoginFailureEntity that)) {
return false;
}
LoginFailureEntity that = (LoginFailureEntity) o; if (!Objects.equals(userId, that.userId)) {
return false;
if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false; }
if (getRealmId() != null ? !getRealmId().equals(that.getRealmId()) : that.getRealmId() != null) return false; return getRealmId() != null ? getRealmId().equals(that.getRealmId()) : that.getRealmId() == null;
return true;
} }
@Override @Override
@ -137,43 +143,4 @@ public class LoginFailureEntity extends SessionEntity {
return String.format("LoginFailureEntity [ userId=%s, realm=%s, numFailures=%d ]", userId, getRealmId(), numFailures); return String.format("LoginFailureEntity [ userId=%s, realm=%s, numFailures=%d ]", userId, getRealmId(), numFailures);
} }
public static class ExternalizerImpl implements Externalizer<LoginFailureEntity> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LoginFailureEntity value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.getRealmId(), output);
MarshallUtil.marshallString(value.userId, output);
output.writeInt(value.failedLoginNotBefore);
output.writeInt(value.numFailures);
output.writeInt(value.numTemporaryLockouts);
output.writeLong(value.lastFailure);
MarshallUtil.marshallString(value.lastIPFailure, output);
}
@Override
public LoginFailureEntity readObject(ObjectInput input) throws IOException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LoginFailureEntity readObjectVersion1(ObjectInput input) throws IOException {
return new LoginFailureEntity(
MarshallUtil.unmarshallString(input),
MarshallUtil.unmarshallString(input),
input.readInt(),
input.readInt(),
input.readInt(),
input.readLong(),
MarshallUtil.unmarshallString(input)
);
}
}
} }

View file

@ -17,77 +17,14 @@
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import java.io.IOException; import org.infinispan.protostream.annotations.Proto;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectOutput; import org.keycloak.marshalling.Marshalling;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@SerializeWith(LoginFailureKey.ExternalizerImpl.class) @ProtoTypeId(Marshalling.LOGIN_FAILURE_KEY)
public class LoginFailureKey { @Proto
public record LoginFailureKey(String realmId, String userId) {
private final String realmId;
private final String userId;
public LoginFailureKey(String realmId, String userId) {
this.realmId = realmId;
this.userId = userId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LoginFailureKey key = (LoginFailureKey) o;
if (realmId != null ? !realmId.equals(key.realmId) : key.realmId != null) return false;
if (userId != null ? !userId.equals(key.userId) : key.userId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = realmId != null ? realmId.hashCode() : 0;
result = 31 * result + (userId != null ? userId.hashCode() : 0);
return result;
}
@Override
public String toString() {
return String.format("LoginFailureKey [ realmId=%s. userId=%s ]", realmId, userId);
}
public static class ExternalizerImpl implements Externalizer<LoginFailureKey> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LoginFailureKey value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.realmId, output);
MarshallUtil.marshallString(value.userId, output);
}
@Override
public LoginFailureKey readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LoginFailureKey readObjectVersion1(ObjectInput input) throws IOException {
return new LoginFailureKey(MarshallUtil.unmarshallString(input), MarshallUtil.unmarshallString(input));
}
}
} }

View file

@ -17,20 +17,19 @@
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil; import org.infinispan.protostream.annotations.ProtoFactory;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoField;
import java.io.ObjectInput; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectOutput; import org.keycloak.marshalling.Marshalling;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RootAuthenticationSessionEntity.ExternalizerImpl.class) @ProtoTypeId(Marshalling.ROOT_AUTHENTICATION_SESSION_ENTITY)
public class RootAuthenticationSessionEntity extends SessionEntity { public class RootAuthenticationSessionEntity extends SessionEntity {
private final String id; private final String id;
@ -48,10 +47,17 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
this.authenticationSessions = authenticationSessions; this.authenticationSessions = authenticationSessions;
} }
@ProtoFactory
static RootAuthenticationSessionEntity protoFactory(String realmId, String id, int timestamp, Map<String, AuthenticationSessionEntity> authenticationSessions) {
return new RootAuthenticationSessionEntity(realmId, id, timestamp, authenticationSessions);
}
@ProtoField(2)
public String getId() { public String getId() {
return id; return id;
} }
@ProtoField(3)
public int getTimestamp() { public int getTimestamp() {
return timestamp; return timestamp;
} }
@ -60,6 +66,7 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@ProtoField(value = 4, mapImplementation = ConcurrentHashMap.class)
public Map<String, AuthenticationSessionEntity> getAuthenticationSessions() { public Map<String, AuthenticationSessionEntity> getAuthenticationSessions() {
return authenticationSessions; return authenticationSessions;
} }
@ -70,14 +77,12 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (!(o instanceof RootAuthenticationSessionEntity)) return false; return true;
}
return o instanceof RootAuthenticationSessionEntity that &&
Objects.equals(id, that.id);
RootAuthenticationSessionEntity that = (RootAuthenticationSessionEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
} }
@Override @Override
@ -90,41 +95,4 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
return String.format("RootAuthenticationSessionEntity [ id=%s, realm=%s ]", getId(), getRealmId()); return String.format("RootAuthenticationSessionEntity [ id=%s, realm=%s ]", getId(), getRealmId());
} }
public static class ExternalizerImpl implements Externalizer<RootAuthenticationSessionEntity> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RootAuthenticationSessionEntity value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.getRealmId(), output);
MarshallUtil.marshallString(value.id, output);
output.writeInt(value.timestamp);
KeycloakMarshallUtil.writeMap(value.authenticationSessions, KeycloakMarshallUtil.STRING_EXT, AuthenticationSessionEntity.ExternalizerImpl.INSTANCE, output);
}
@Override
public RootAuthenticationSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RootAuthenticationSessionEntity readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return new RootAuthenticationSessionEntity(
MarshallUtil.unmarshallString(input), // realmId
MarshallUtil.unmarshallString(input), // id
input.readInt(), // timestamp
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, AuthenticationSessionEntity.ExternalizerImpl.INSTANCE, size -> new ConcurrentHashMap<>(size)) // authenticationSessions
);
}
}
} }

View file

@ -17,8 +17,7 @@
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import java.io.Serializable; import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
@ -30,7 +29,7 @@ import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
* *
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public abstract class SessionEntity implements Serializable { public abstract class SessionEntity {
private String realmId; private String realmId;
private boolean isOffline; private boolean isOffline;
@ -39,6 +38,7 @@ public abstract class SessionEntity implements Serializable {
* Returns realmId ID. * Returns realmId ID.
* @return * @return
*/ */
@ProtoField(1)
public String getRealmId() { public String getRealmId() {
return realmId; return realmId;
} }
@ -60,7 +60,7 @@ public abstract class SessionEntity implements Serializable {
} else { } else {
return new SessionEntityWrapper<>(localEntityWrapper.getLocalMetadata(), this); return new SessionEntityWrapper<>(localEntityWrapper.getLocalMetadata(), this);
} }
}; }
@Override @Override
public abstract boolean equals(Object obj); public abstract boolean equals(Object obj);

View file

@ -16,28 +16,40 @@
*/ */
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import org.keycloak.models.SingleUseObjectValueModel; import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.io.*; import org.infinispan.protostream.annotations.ProtoFactory;
import java.util.*; import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.commons.marshall.Externalizer; import org.infinispan.protostream.annotations.ProtoTypeId;
import org.infinispan.commons.marshall.SerializeWith; import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.SingleUseObjectValueModel;
/** /**
* @author hmlnarik * @author hmlnarik
*/ */
@SerializeWith(SingleUseObjectValueEntity.ExternalizerImpl.class) @ProtoTypeId(Marshalling.SINGLE_USE_OBJECT_VALUE_ENTITY)
public class SingleUseObjectValueEntity implements SingleUseObjectValueModel { public class SingleUseObjectValueEntity implements SingleUseObjectValueModel {
private final Map<String, String> notes; private final Map<String, String> notes;
@ProtoFactory
public SingleUseObjectValueEntity(Map<String, String> notes) { public SingleUseObjectValueEntity(Map<String, String> notes) {
this.notes = notes == null ? Collections.EMPTY_MAP : new HashMap<>(notes); if (notes == null || notes.isEmpty()) {
this.notes = Map.of();
return;
}
var copy = new HashMap<>(notes);
// protostream does not support null values for primitive types as string
copy.values().removeIf(Objects::isNull);
this.notes = Map.copyOf(copy);
} }
@ProtoField(value = 1, mapImplementation = HashMap.class)
@Override @Override
public Map<String, String> getNotes() { public Map<String, String> getNotes() {
return Collections.unmodifiableMap(notes); return notes;
} }
@Override @Override
@ -50,32 +62,4 @@ public class SingleUseObjectValueEntity implements SingleUseObjectValueModel {
return String.format("SingleUseObjectValueEntity [ notes=%s ]", notes.toString()); return String.format("SingleUseObjectValueEntity [ notes=%s ]", notes.toString());
} }
public static class ExternalizerImpl implements Externalizer<SingleUseObjectValueEntity> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, SingleUseObjectValueEntity t) throws IOException {
output.writeByte(VERSION_1);
output.writeBoolean(t.notes.isEmpty());
if (! t.notes.isEmpty()) {
output.writeObject(t.notes);
}
}
@Override
public SingleUseObjectValueEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
byte version = input.readByte();
if (version != VERSION_1) {
throw new IOException("Invalid version: " + version);
}
boolean notesEmpty = input.readBoolean();
Map<String, String> notes = notesEmpty ? Collections.EMPTY_MAP : (Map<String, String>) input.readObject();
return new SingleUseObjectValueEntity(notes);
}
}
} }

View file

@ -17,29 +17,23 @@
package org.keycloak.models.sessions.infinispan.entities; package org.keycloak.models.sessions.infinispan.entities;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.jboss.logging.Logger;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionModel.State;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Objects;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.jboss.logging.Logger;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@SerializeWith(UserSessionEntity.ExternalizerImpl.class) @ProtoTypeId(Marshalling.USER_SESSION_ENTITY)
public class UserSessionEntity extends SessionEntity { public class UserSessionEntity extends SessionEntity {
public static final Logger logger = Logger.getLogger(UserSessionEntity.class); public static final Logger logger = Logger.getLogger(UserSessionEntity.class);
@ -72,6 +66,26 @@ public class UserSessionEntity extends SessionEntity {
this.id = id; this.id = id;
} }
@ProtoFactory
static UserSessionEntity protoFactory(String realmId, String id, String user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, int started, int lastSessionRefresh, Map<String, String> notes, AuthenticatedClientSessionStore authenticatedClientSessions, UserSessionModel.State state, String brokerSessionId, String brokerUserId) {
var entity = new UserSessionEntity(id);
entity.setRealmId(realmId);
entity.setUser(user);
entity.setLoginUsername(loginUsername);
entity.setIpAddress(ipAddress);
entity.setAuthMethod(authMethod);
entity.setRememberMe(rememberMe);
entity.setStarted(started);
entity.setLastSessionRefresh(lastSessionRefresh);
entity.setBrokerSessionId(brokerSessionId);
entity.setBrokerUserId(brokerUserId);
entity.setState(state);
entity.setNotes(notes);
entity.setAuthenticatedClientSessions(authenticatedClientSessions);
return entity;
}
@ProtoField(2)
public String getId() { public String getId() {
return id; return id;
} }
@ -80,6 +94,7 @@ public class UserSessionEntity extends SessionEntity {
private AuthenticatedClientSessionStore authenticatedClientSessions = new AuthenticatedClientSessionStore(); private AuthenticatedClientSessionStore authenticatedClientSessions = new AuthenticatedClientSessionStore();
@ProtoField(3)
public String getUser() { public String getUser() {
return user; return user;
} }
@ -88,6 +103,7 @@ public class UserSessionEntity extends SessionEntity {
this.user = user; this.user = user;
} }
@ProtoField(4)
public String getLoginUsername() { public String getLoginUsername() {
return loginUsername; return loginUsername;
} }
@ -96,6 +112,7 @@ public class UserSessionEntity extends SessionEntity {
this.loginUsername = loginUsername; this.loginUsername = loginUsername;
} }
@ProtoField(5)
public String getIpAddress() { public String getIpAddress() {
return ipAddress; return ipAddress;
} }
@ -104,6 +121,7 @@ public class UserSessionEntity extends SessionEntity {
this.ipAddress = ipAddress; this.ipAddress = ipAddress;
} }
@ProtoField(6)
public String getAuthMethod() { public String getAuthMethod() {
return authMethod; return authMethod;
} }
@ -112,6 +130,7 @@ public class UserSessionEntity extends SessionEntity {
this.authMethod = authMethod; this.authMethod = authMethod;
} }
@ProtoField(7)
public boolean isRememberMe() { public boolean isRememberMe() {
return rememberMe; return rememberMe;
} }
@ -120,6 +139,7 @@ public class UserSessionEntity extends SessionEntity {
this.rememberMe = rememberMe; this.rememberMe = rememberMe;
} }
@ProtoField(8)
public int getStarted() { public int getStarted() {
return started; return started;
} }
@ -128,6 +148,7 @@ public class UserSessionEntity extends SessionEntity {
this.started = started; this.started = started;
} }
@ProtoField(9)
public int getLastSessionRefresh() { public int getLastSessionRefresh() {
return lastSessionRefresh; return lastSessionRefresh;
} }
@ -136,6 +157,7 @@ public class UserSessionEntity extends SessionEntity {
this.lastSessionRefresh = lastSessionRefresh; this.lastSessionRefresh = lastSessionRefresh;
} }
@ProtoField(value = 10, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getNotes() { public Map<String, String> getNotes() {
return notes; return notes;
} }
@ -144,6 +166,7 @@ public class UserSessionEntity extends SessionEntity {
this.notes = notes; this.notes = notes;
} }
@ProtoField(11)
public AuthenticatedClientSessionStore getAuthenticatedClientSessions() { public AuthenticatedClientSessionStore getAuthenticatedClientSessions() {
return authenticatedClientSessions; return authenticatedClientSessions;
} }
@ -152,6 +175,7 @@ public class UserSessionEntity extends SessionEntity {
this.authenticatedClientSessions = authenticatedClientSessions; this.authenticatedClientSessions = authenticatedClientSessions;
} }
@ProtoField(value = 12)
public UserSessionModel.State getState() { public UserSessionModel.State getState() {
return state; return state;
} }
@ -160,6 +184,7 @@ public class UserSessionEntity extends SessionEntity {
this.state = state; this.state = state;
} }
@ProtoField(13)
public String getBrokerSessionId() { public String getBrokerSessionId() {
return brokerSessionId; return brokerSessionId;
} }
@ -168,6 +193,7 @@ public class UserSessionEntity extends SessionEntity {
this.brokerSessionId = brokerSessionId; this.brokerSessionId = brokerSessionId;
} }
@ProtoField(14)
public String getBrokerUserId() { public String getBrokerUserId() {
return brokerUserId; return brokerUserId;
} }
@ -178,14 +204,12 @@ public class UserSessionEntity extends SessionEntity {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (!(o instanceof UserSessionEntity)) return false; return true;
}
return o instanceof UserSessionEntity that &&
Objects.equals(id, that.id);
UserSessionEntity that = (UserSessionEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
} }
@Override @Override
@ -224,88 +248,4 @@ public class UserSessionEntity extends SessionEntity {
return entityWrapper; return entityWrapper;
} }
public static class ExternalizerImpl implements Externalizer<UserSessionEntity> {
private static final int VERSION_1 = 1;
private static final EnumMap<UserSessionModel.State, Integer> STATE_TO_ID = new EnumMap<>(UserSessionModel.State.class);
private static final Map<Integer, UserSessionModel.State> ID_TO_STATE = new HashMap<>();
static {
STATE_TO_ID.put(State.LOGGED_IN, 1);
STATE_TO_ID.put(State.LOGGED_OUT, 2);
STATE_TO_ID.put(State.LOGGING_OUT, 3);
for (Entry<State, Integer> entry : STATE_TO_ID.entrySet()) {
ID_TO_STATE.put(entry.getValue(), entry.getKey());
}
}
@Override
public void writeObject(ObjectOutput output, UserSessionEntity session) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(session.getAuthMethod(), output);
MarshallUtil.marshallString(session.getBrokerSessionId(), output);
MarshallUtil.marshallString(session.getBrokerUserId(), output);
MarshallUtil.marshallString(session.getId(), output);
MarshallUtil.marshallString(session.getIpAddress(), output);
MarshallUtil.marshallString(session.getLoginUsername(), output);
MarshallUtil.marshallString(session.getRealmId(), output);
MarshallUtil.marshallString(session.getUser(), output);
KeycloakMarshallUtil.marshall(session.getLastSessionRefresh(), output);
KeycloakMarshallUtil.marshall(session.getStarted(), output);
output.writeBoolean(session.isRememberMe());
int state = session.getState() == null ? 0 : STATE_TO_ID.get(session.getState());
output.writeInt(state);
Map<String, String> notes = session.getNotes();
KeycloakMarshallUtil.writeMap(notes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
output.writeObject(session.getAuthenticatedClientSessions());
}
@Override
public UserSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserSessionEntity readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
String authMethod = MarshallUtil.unmarshallString(input);
String brokerSessionId = MarshallUtil.unmarshallString(input);
String brokerUserId = MarshallUtil.unmarshallString(input);
UserSessionEntity sessionEntity = new UserSessionEntity(MarshallUtil.unmarshallString(input));
sessionEntity.setAuthMethod(authMethod);
sessionEntity.setBrokerSessionId(brokerSessionId);
sessionEntity.setBrokerUserId(brokerUserId);
sessionEntity.setIpAddress(MarshallUtil.unmarshallString(input));
sessionEntity.setLoginUsername(MarshallUtil.unmarshallString(input));
sessionEntity.setRealmId(MarshallUtil.unmarshallString(input));
sessionEntity.setUser(MarshallUtil.unmarshallString(input));
sessionEntity.setLastSessionRefresh(KeycloakMarshallUtil.unmarshallInteger(input));
sessionEntity.setStarted(KeycloakMarshallUtil.unmarshallInteger(input));
sessionEntity.setRememberMe(input.readBoolean());
sessionEntity.setState(ID_TO_STATE.get(input.readInt()));
Map<String, String> notes = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT,
new KeycloakMarshallUtil.ConcurrentHashMapBuilder<>());
sessionEntity.setNotes(notes);
AuthenticatedClientSessionStore authSessions = (AuthenticatedClientSessionStore) input.readObject();
sessionEntity.setAuthenticatedClientSessions(authSessions);
return sessionEntity;
}
}
} }

View file

@ -17,45 +17,13 @@
package org.keycloak.models.sessions.infinispan.events; package org.keycloak.models.sessions.infinispan.events;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectInput; import org.keycloak.marshalling.Marshalling;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RealmRemovedSessionEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.REALM_REMOVED_SESSION_EVENT)
public class RealmRemovedSessionEvent extends SessionClusterEvent { public class RealmRemovedSessionEvent extends SessionClusterEvent {
public static class ExternalizerImpl implements Externalizer<RealmRemovedSessionEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RealmRemovedSessionEvent obj) throws IOException {
output.writeByte(VERSION_1);
obj.marshallTo(output);
}
@Override
public RealmRemovedSessionEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RealmRemovedSessionEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RealmRemovedSessionEvent res = new RealmRemovedSessionEvent();
res.unmarshallFrom(input);
return res;
}
}
} }

View file

@ -17,45 +17,13 @@
package org.keycloak.models.sessions.infinispan.events; package org.keycloak.models.sessions.infinispan.events;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectInput; import org.keycloak.marshalling.Marshalling;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RemoveAllUserLoginFailuresEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.REMOVE_ALL_USER_LOGIN_FAILURES_EVENT)
public class RemoveAllUserLoginFailuresEvent extends SessionClusterEvent { public class RemoveAllUserLoginFailuresEvent extends SessionClusterEvent {
public static class ExternalizerImpl implements Externalizer<RemoveAllUserLoginFailuresEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RemoveAllUserLoginFailuresEvent obj) throws IOException {
output.writeByte(VERSION_1);
obj.marshallTo(output);
}
@Override
public RemoveAllUserLoginFailuresEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RemoveAllUserLoginFailuresEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RemoveAllUserLoginFailuresEvent res = new RemoveAllUserLoginFailuresEvent();
res.unmarshallFrom(input);
return res;
}
}
} }

View file

@ -17,45 +17,13 @@
package org.keycloak.models.sessions.infinispan.events; package org.keycloak.models.sessions.infinispan.events;
import java.io.IOException; import org.infinispan.protostream.annotations.ProtoTypeId;
import java.io.ObjectInput; import org.keycloak.marshalling.Marshalling;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@SerializeWith(RemoveUserSessionsEvent.ExternalizerImpl.class) @ProtoTypeId(Marshalling.REMOVE_ALL_USER_SESSIONS_EVENT)
public class RemoveUserSessionsEvent extends SessionClusterEvent { public class RemoveUserSessionsEvent extends SessionClusterEvent {
public static class ExternalizerImpl implements Externalizer<RemoveUserSessionsEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RemoveUserSessionsEvent obj) throws IOException {
output.writeByte(VERSION_1);
obj.marshallTo(output);
}
@Override
public RemoveUserSessionsEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RemoveUserSessionsEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RemoveUserSessionsEvent res = new RemoveUserSessionsEvent();
res.unmarshallFrom(input);
return res;
}
}
} }

View file

@ -17,16 +17,13 @@
package org.keycloak.models.sessions.infinispan.events; package org.keycloak.models.sessions.infinispan.events;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession;
import org.keycloak.connections.infinispan.InfinispanUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects; import java.util.Objects;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -42,7 +39,7 @@ public abstract class SessionClusterEvent implements ClusterEvent {
public static <T extends SessionClusterEvent> T createEvent(Class<T> eventClass, String eventKey, KeycloakSession session, String realmId, boolean resendingEvent) { public static <T extends SessionClusterEvent> T createEvent(Class<T> eventClass, String eventKey, KeycloakSession session, String realmId, boolean resendingEvent) {
try { try {
T event = eventClass.newInstance(); T event = eventClass.getDeclaredConstructor().newInstance();
event.setData(session, eventKey, realmId, resendingEvent); event.setData(session, eventKey, realmId, resendingEvent);
return event; return event;
} catch (Exception e) { } catch (Exception e) {
@ -61,26 +58,51 @@ public abstract class SessionClusterEvent implements ClusterEvent {
} }
@ProtoField(1)
public String getRealmId() { public String getRealmId() {
return realmId; return realmId;
} }
void setRealmId(String realmId) {
this.realmId = realmId;
}
@ProtoField(2)
public String getEventKey() { public String getEventKey() {
return eventKey; return eventKey;
} }
void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
@ProtoField(3)
public boolean isResendingEvent() { public boolean isResendingEvent() {
return resendingEvent; return resendingEvent;
} }
void setResendingEvent(boolean resendingEvent) {
this.resendingEvent = resendingEvent;
}
@ProtoField(4)
public String getSiteId() { public String getSiteId() {
return siteId; return siteId;
} }
void setSiteId(String siteId) {
this.siteId = siteId;
}
@ProtoField(5)
public String getNodeId() { public String getNodeId() {
return nodeId; return nodeId;
} }
void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
@ -99,40 +121,4 @@ public abstract class SessionClusterEvent implements ClusterEvent {
String simpleClassName = getClass().getSimpleName(); String simpleClassName = getClass().getSimpleName();
return String.format("%s [ realmId=%s ]", simpleClassName, realmId); return String.format("%s [ realmId=%s ]", simpleClassName, realmId);
} }
// Infinispan marshalling support for child classes
private static final int VERSION_1 = 1;
protected void marshallTo(ObjectOutput output) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(realmId, output);
MarshallUtil.marshallString(eventKey, output);
output.writeBoolean(resendingEvent);
MarshallUtil.marshallString(siteId, output);
MarshallUtil.marshallString(nodeId, output);
}
/**
* Sets the properties of this object from the input stream.
* @param input
* @throws IOException
*/
protected void unmarshallFrom(ObjectInput input) throws IOException {
switch (input.readByte()) {
case VERSION_1:
unmarshallFromVersion1(input);
break;
default:
throw new IOException("Unknown version");
}
}
private void unmarshallFromVersion1(ObjectInput input) throws IOException {
this.realmId = MarshallUtil.unmarshallString(input);
this.eventKey = MarshallUtil.unmarshallString(input);
this.resendingEvent = input.readBoolean();
this.siteId = MarshallUtil.unmarshallString(input);
this.nodeId = MarshallUtil.unmarshallString(input);
}
} }

View file

@ -23,8 +23,6 @@ import org.infinispan.lifecycle.ComponentStatus;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import java.io.Serializable;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -35,11 +33,11 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
private static final Logger log = Logger.getLogger(BaseCacheInitializer.class); private static final Logger log = Logger.getLogger(BaseCacheInitializer.class);
protected final KeycloakSessionFactory sessionFactory; protected final KeycloakSessionFactory sessionFactory;
protected final Cache<String, Serializable> workCache; protected final Cache<String, InitializerState> workCache;
protected final SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader; protected final SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader;
protected final String stateKey; protected final String stateKey;
public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader, String stateKeySuffix) { public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, InitializerState> workCache, SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader, String stateKeySuffix) {
this.sessionFactory = sessionFactory; this.sessionFactory = sessionFactory;
this.workCache = workCache; this.workCache = workCache;
this.sessionLoader = sessionLoader; this.sessionLoader = sessionLoader;
@ -67,7 +65,7 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
protected InitializerState getStateFromCache() { protected InitializerState getStateFromCache() {
// We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored. // We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored.
return (InitializerState) workCache.getAdvancedCache() return workCache.getAdvancedCache()
.withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD) .withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD)
.get(stateKey); .get(stateKey);
} }

Some files were not shown because too many files have changed in this diff Show more