KEYCLOAK-18369 Create MapKeycloakTransaction interface
This commit is contained in:
parent
7ffa2835ef
commit
d2a8a95d79
16 changed files with 574 additions and 458 deletions
|
@ -142,7 +142,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
public PermissionTicket findById(String id, String resourceServerId) {
|
||||
LOG.tracef("findById(%s, %s)%s", id, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(PermissionTicket.SearchableFields.ID, Operator.EQ, id))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
|
@ -153,7 +153,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
public List<PermissionTicket> findByResourceServer(String resourceServerId) {
|
||||
LOG.tracef("findByResourceServer(%s)%s", resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId))
|
||||
return tx.read(forResourceServer(resourceServerId))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
public List<PermissionTicket> findByOwner(String owner, String resourceServerId) {
|
||||
LOG.tracef("findByOwner(%s, %s)%s", owner, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, owner))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -172,7 +172,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
public List<PermissionTicket> findByResource(String resourceId, String resourceServerId) {
|
||||
LOG.tracef("findByResource(%s, %s)%s", resourceId, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.RESOURCE_ID, Operator.EQ, resourceId))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -182,7 +182,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
public List<PermissionTicket> findByScope(String scopeId, String resourceServerId) {
|
||||
LOG.tracef("findByScope(%s, %s)%s", scopeId, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.EQ, scopeId))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -213,7 +213,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
);
|
||||
|
||||
Comparator<? super MapPermissionTicketEntity<K>> c = Comparator.comparing(MapPermissionTicketEntity::getId);
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(c), firstResult, maxResult)
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -297,7 +297,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
.findById(ticket.getResourceId(), ticket.getResourceServerId());
|
||||
}
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.filter(distinctByKey(MapPermissionTicketEntity::getResourceId))
|
||||
.sorted(MapPermissionTicketEntity.COMPARE_BY_RESOURCE_ID)
|
||||
.map(ticketResourceMapper)
|
||||
|
@ -310,7 +310,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
ModelCriteriaBuilder<PermissionTicket> mcb = permissionTicketStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, owner);
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.filter(distinctByKey(MapPermissionTicketEntity::getResourceId))
|
||||
.sorted(MapPermissionTicketEntity.COMPARE_BY_RESOURCE_ID), first, max)
|
||||
.map(ticket -> authorizationProvider.getStoreFactory().getResourceStore()
|
||||
|
|
|
@ -111,7 +111,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
public Policy findById(String id, String resourceServerId) {
|
||||
LOG.tracef("findById(%s, %s)%s", id, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
|
@ -122,7 +122,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
public Policy findByName(String name, String resourceServerId) {
|
||||
LOG.tracef("findByName(%s, %s)%s", name, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
|
@ -133,7 +133,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
public List<Policy> findByResourceServer(String id) {
|
||||
LOG.tracef("findByResourceServer(%s)%s", id, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(id))
|
||||
return tx.read(forResourceServer(id))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
mcb = mcb.compare(SearchableFields.OWNER, Operator.NOT_EXISTS);
|
||||
}
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(MapPolicyEntity.COMPARE_BY_NAME), firstResult, maxResult)
|
||||
.map(MapPolicyEntity<K>::getId)
|
||||
.map(K::toString)
|
||||
|
@ -205,7 +205,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
public void findByResource(String resourceId, String resourceServerId, Consumer<Policy> consumer) {
|
||||
LOG.tracef("findByResource(%s, %s, %s)%s", resourceId, resourceServerId, consumer, getShortStackTrace());
|
||||
|
||||
tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
tx.read(forResourceServer(resourceServerId)
|
||||
.compare(Policy.SearchableFields.RESOURCE_ID, Operator.EQ, resourceId))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
|
@ -213,7 +213,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public void findByResourceType(String type, String resourceServerId, Consumer<Policy> policyConsumer) {
|
||||
tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.CONFIG, Operator.LIKE, (Object[]) new String[] {"defaultResourceType", type}))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(policyConsumer);
|
||||
|
@ -221,7 +221,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopeIds))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -241,12 +241,12 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
.compare(SearchableFields.CONFIG, Operator.NOT_EXISTS, (Object[]) new String[] {"defaultResourceType"});
|
||||
}
|
||||
|
||||
tx.getUpdatedNotRemoved(mcb).map(this::entityToAdapter).forEach(consumer);
|
||||
tx.read(mcb).map(this::entityToAdapter).forEach(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByType(String type, String resourceServerId) {
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -254,7 +254,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public List<Policy> findDependentPolicies(String id, String resourceServerId) {
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ASSOCIATED_POLICY_ID, Operator.EQ, id))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -113,7 +113,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
public Resource findById(String id, String resourceServerId) {
|
||||
LOG.tracef("findById(%s, %s)%s", id, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
|
@ -128,7 +128,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
private void findByOwnerFilter(String ownerId, String resourceServerId, Consumer<Resource> consumer, int firstResult, int maxResult) {
|
||||
LOG.tracef("findByOwnerFilter(%s, %s, %s, %d, %d)%s", ownerId, resourceServerId, consumer, firstResult, maxResult, getShortStackTrace());
|
||||
Comparator<? super MapResourceEntity<K>> c = Comparator.comparing(MapResourceEntity::getId);
|
||||
paginatedStream(tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
paginatedStream(tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, ownerId))
|
||||
.sorted(c), firstResult, maxResult)
|
||||
.map(this::entityToAdapter)
|
||||
|
@ -148,7 +148,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
public List<Resource> findByUri(String uri, String resourceServerId) {
|
||||
LOG.tracef("findByUri(%s, %s)%s", uri, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.URI, Operator.EQ, uri))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -158,7 +158,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
public List<Resource> findByResourceServer(String resourceServerId) {
|
||||
LOG.tracef("findByResourceServer(%s)%s", resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId))
|
||||
return tx.read(forResourceServer(resourceServerId))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
.toArray(ModelCriteriaBuilder[]::new)
|
||||
);
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(MapResourceEntity.COMPARE_BY_NAME), firstResult, maxResult)
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -210,7 +210,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
public void findByScope(List<String> scopes, String resourceServerId, Consumer<Resource> consumer) {
|
||||
LOG.tracef("findByScope(%s, %s, %s)%s", scopes, resourceServerId, consumer, getShortStackTrace());
|
||||
|
||||
tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopes))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
|
@ -224,7 +224,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
@Override
|
||||
public Resource findByName(String name, String ownerId, String resourceServerId) {
|
||||
LOG.tracef("findByName(%s, %s, %s)%s", name, ownerId, resourceServerId, getShortStackTrace());
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, ownerId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name))
|
||||
.findFirst()
|
||||
|
@ -235,7 +235,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
@Override
|
||||
public void findByType(String type, String resourceServerId, Consumer<Resource> consumer) {
|
||||
LOG.tracef("findByType(%s, %s, %s)%s", type, resourceServerId, consumer, getShortStackTrace());
|
||||
tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
|
@ -252,7 +252,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
mcb = mcb.compare(SearchableFields.OWNER, Operator.EQ, owner);
|
||||
}
|
||||
|
||||
tx.getUpdatedNotRemoved(mcb)
|
||||
tx.read(mcb)
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
@Override
|
||||
public void findByTypeInstance(String type, String resourceServerId, Consumer<Resource> consumer) {
|
||||
LOG.tracef("findByTypeInstance(%s, %s, %s)%s", type, resourceServerId, consumer, getShortStackTrace());
|
||||
tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.NE, resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type))
|
||||
.map(this::entityToAdapter)
|
||||
|
|
|
@ -109,7 +109,7 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
public Scope findById(String id, String resourceServerId) {
|
||||
LOG.tracef("findById(%s, %s)%s", id, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId)
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(Scope.SearchableFields.ID, Operator.EQ, id))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
|
@ -120,7 +120,7 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
public Scope findByName(String name, String resourceServerId) {
|
||||
LOG.tracef("findByName(%s, %s)%s", name, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(resourceServerId).compare(Scope.SearchableFields.NAME,
|
||||
return tx.read(forResourceServer(resourceServerId).compare(Scope.SearchableFields.NAME,
|
||||
Operator.EQ, name))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
|
@ -131,7 +131,7 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
public List<Scope> findByResourceServer(String id) {
|
||||
LOG.tracef("findByResourceServer(%s)%s", id, getShortStackTrace());
|
||||
|
||||
return tx.getUpdatedNotRemoved(forResourceServer(id))
|
||||
return tx.read(forResourceServer(id))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
}
|
||||
}
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb).map(this::entityToAdapter), firstResult, maxResult)
|
||||
return paginatedStream(tx.read(mcb).map(this::entityToAdapter), firstResult, maxResult)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
ModelCriteriaBuilder<ClientModel> mcb = clientStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.sorted(COMPARE_BY_CLIENT_ID)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
;
|
||||
|
@ -248,7 +248,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.CLIENT_ID, Operator.ILIKE, clientId);
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.findFirst()
|
||||
.orElse(null)
|
||||
|
@ -265,7 +265,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.CLIENT_ID, Operator.ILIKE, "%" + clientId + "%");
|
||||
|
||||
Stream<MapClientEntity<K>> s = tx.getUpdatedNotRemoved(mcb)
|
||||
Stream<MapClientEntity<K>> s = tx.read(mcb)
|
||||
.sorted(COMPARE_BY_CLIENT_ID);
|
||||
|
||||
return paginatedStream(s, firstResult, maxResults).map(entityToAdapterFunc(realm));
|
||||
|
@ -280,7 +280,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
mcb = mcb.compare(SearchableFields.ATTRIBUTE, Operator.EQ, entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
Stream<MapClientEntity<K>> s = tx.getUpdatedNotRemoved(mcb)
|
||||
Stream<MapClientEntity<K>> s = tx.read(mcb)
|
||||
.sorted(COMPARE_BY_CLIENT_ID);
|
||||
|
||||
return paginatedStream(s, firstResult, maxResults).map(entityToAdapterFunc(realm));
|
||||
|
@ -344,7 +344,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.ENABLED, Operator.EQ, Boolean.TRUE);
|
||||
|
||||
try (Stream<MapClientEntity<K>> st = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapClientEntity<K>> st = tx.read(mcb)) {
|
||||
return st
|
||||
.filter(mce -> mce.getRedirectUris() != null && ! mce.getRedirectUris().isEmpty())
|
||||
.collect(Collectors.toMap(
|
||||
|
@ -358,7 +358,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
ModelCriteriaBuilder<ClientModel> mcb = clientStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.SCOPE_MAPPING_ROLE, Operator.EQ, role.getId());
|
||||
try (Stream<MapClientEntity<K>> toRemove = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapClientEntity<K>> toRemove = tx.read(mcb)) {
|
||||
toRemove
|
||||
.map(clientEntity -> session.clients().getClientById(realm, clientEntity.getId().toString()))
|
||||
.filter(Objects::nonNull)
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.keycloak.models.ClientScopeModel;
|
|||
import org.keycloak.models.ClientScopeProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
|
@ -80,7 +79,7 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
|
|||
ModelCriteriaBuilder<ClientScopeModel> mcb = clientScopeStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME)
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
mcb = modifier.apply(mcb);
|
||||
}
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.sorted(GroupModel.COMPARE_BY_NAME)
|
||||
;
|
||||
|
@ -116,7 +116,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
mcb = mcb.compare(SearchableFields.NAME, Operator.ILIKE, "%" + search + "%");
|
||||
}
|
||||
|
||||
Stream<GroupModel> groupModelStream = tx.getUpdatedNotRemoved(mcb)
|
||||
Stream<GroupModel> groupModelStream = tx.read(mcb)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.sorted(Comparator.comparing(GroupModel::getName));
|
||||
|
||||
|
@ -261,7 +261,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
.compare(SearchableFields.PARENT_ID, Operator.EQ, parentId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, group.getName());
|
||||
|
||||
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.read(mcb)) {
|
||||
if (possibleSiblings.findAny().isPresent()) {
|
||||
throw new ModelDuplicateException("Parent already contains subgroup named '" + group.getName() + "'");
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
.compare(SearchableFields.PARENT_ID, Operator.EQ, (Object) null)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, subGroup.getName());
|
||||
|
||||
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.read(mcb)) {
|
||||
if (possibleSiblings.findAny().isPresent()) {
|
||||
throw new ModelDuplicateException("There is already a top level group named '" + subGroup.getName() + "'");
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
ModelCriteriaBuilder<GroupModel> mcb = groupStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.ASSIGNED_ROLE, Operator.EQ, role.getId());
|
||||
try (Stream<MapGroupEntity<K>> toRemove = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapGroupEntity<K>> toRemove = tx.read(mcb)) {
|
||||
toRemove
|
||||
.map(groupEntity -> session.groups().getGroupById(realm, groupEntity.getId().toString()))
|
||||
.forEach(groupModel -> groupModel.deleteRoleMapping(role));
|
||||
|
|
|
@ -66,7 +66,7 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
|
|||
|
||||
LOG.tracef("getUserLoginFailure(%s, %s)%s", realm, userId, getShortStackTrace());
|
||||
|
||||
return userLoginFailureTx.getUpdatedNotRemoved(mcb)
|
||||
return userLoginFailureTx.read(mcb)
|
||||
.findFirst()
|
||||
.map(userLoginFailureEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -80,7 +80,7 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
|
|||
|
||||
LOG.tracef("addUserLoginFailure(%s, %s)%s", realm, userId, getShortStackTrace());
|
||||
|
||||
MapUserLoginFailureEntity<K> userLoginFailureEntity = userLoginFailureTx.getUpdatedNotRemoved(mcb).findFirst().orElse(null);
|
||||
MapUserLoginFailureEntity<K> userLoginFailureEntity = userLoginFailureTx.read(mcb).findFirst().orElse(null);
|
||||
|
||||
if (userLoginFailureEntity == null) {
|
||||
userLoginFailureEntity = new MapUserLoginFailureEntity<>(userLoginFailureStore.getKeyConvertor().yieldNewUniqueKey(), realm.getId(), userId);
|
||||
|
|
|
@ -110,7 +110,7 @@ public class MapRealmProvider<K> implements RealmProvider {
|
|||
ModelCriteriaBuilder<RealmModel> mcb = realmStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name);
|
||||
|
||||
K realmId = tx.getUpdatedNotRemoved(mcb)
|
||||
K realmId = tx.read(mcb)
|
||||
.findFirst()
|
||||
.map(MapRealmEntity<K>::getId)
|
||||
.orElse(null);
|
||||
|
@ -132,7 +132,7 @@ public class MapRealmProvider<K> implements RealmProvider {
|
|||
}
|
||||
|
||||
private Stream<RealmModel> getRealmsStream(ModelCriteriaBuilder<RealmModel> mcb) {
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.map(this::entityToAdapter)
|
||||
.sorted(RealmModel.COMPARE_BY_NAME);
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ public class MapRealmProvider<K> implements RealmProvider {
|
|||
ModelCriteriaBuilder<RealmModel> mcb = realmStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.CLIENT_INITIAL_ACCESS, Operator.EXISTS);
|
||||
|
||||
tx.getUpdatedNotRemoved(mcb)
|
||||
tx.read(mcb)
|
||||
.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(MapRealmEntity<K>::removeExpiredClientInitialAccesses);
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.IS_CLIENT_ROLE, Operator.NE, true);
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME)
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, client.getRealm().getId())
|
||||
.compare(SearchableFields.CLIENT_ID, Operator.EQ, client.getId());
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME)
|
||||
.map(entityToAdapterFunc(client.getRealm()));
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.IS_COMPOSITE_ROLE, Operator.EQ, false);
|
||||
|
||||
//remove role from realm-roles composites
|
||||
try (Stream<MapRoleEntity<K>> baseStream = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapRoleEntity<K>> baseStream = tx.read(mcb)) {
|
||||
|
||||
StreamUtils.leftInnerJoinIterable(baseStream, MapRoleEntity<K>::getCompositeRoles)
|
||||
.filter(pair -> role.getId().equals(pair.getV()))
|
||||
|
@ -189,7 +189,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.CLIENT_ID, Operator.EQ, client.getId())
|
||||
.compare(SearchableFields.IS_COMPOSITE_ROLE, Operator.EQ, false);
|
||||
|
||||
try (Stream<MapRoleEntity<K>> baseStream = tx.getUpdatedNotRemoved(mcbClient)) {
|
||||
try (Stream<MapRoleEntity<K>> baseStream = tx.read(mcbClient)) {
|
||||
|
||||
StreamUtils.leftInnerJoinIterable(baseStream, MapRoleEntity<K>::getCompositeRoles)
|
||||
.filter(pair -> role.getId().equals(pair.getV()))
|
||||
|
@ -246,7 +246,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.NAME, Operator.ILIKE, name);
|
||||
|
||||
String roleId = tx.getUpdatedNotRemoved(mcb)
|
||||
String roleId = tx.read(mcb)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.map(RoleModel::getId)
|
||||
.findFirst()
|
||||
|
@ -267,7 +267,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.CLIENT_ID, Operator.EQ, client.getId())
|
||||
.compare(SearchableFields.NAME, Operator.ILIKE, name);
|
||||
|
||||
String roleId = tx.getUpdatedNotRemoved(mcb)
|
||||
String roleId = tx.read(mcb)
|
||||
.map(entityToAdapterFunc(client.getRealm()))
|
||||
.map(RoleModel::getId)
|
||||
.findFirst()
|
||||
|
@ -303,7 +303,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
roleStore.createCriteriaBuilder().compare(SearchableFields.DESCRIPTION, Operator.ILIKE, "%" + search + "%")
|
||||
);
|
||||
|
||||
Stream<MapRoleEntity<K>> s = tx.getUpdatedNotRemoved(mcb)
|
||||
Stream<MapRoleEntity<K>> s = tx.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME);
|
||||
|
||||
return paginatedStream(s.map(entityToAdapterFunc(realm)), first, max);
|
||||
|
@ -321,7 +321,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
roleStore.createCriteriaBuilder().compare(SearchableFields.NAME, Operator.ILIKE, "%" + search + "%"),
|
||||
roleStore.createCriteriaBuilder().compare(SearchableFields.DESCRIPTION, Operator.ILIKE, "%" + search + "%")
|
||||
);
|
||||
Stream<MapRoleEntity<K>> s = tx.getUpdatedNotRemoved(mcb)
|
||||
Stream<MapRoleEntity<K>> s = tx.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME);
|
||||
|
||||
return paginatedStream(s,first, max).map(entityToAdapterFunc(client.getRealm()));
|
||||
|
|
|
@ -17,389 +17,109 @@
|
|||
package org.keycloak.models.map.storage;
|
||||
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public class MapKeycloakTransaction<K, V extends AbstractEntity<K>, M> implements KeycloakTransaction {
|
||||
|
||||
private final static Logger log = Logger.getLogger(MapKeycloakTransaction.class);
|
||||
|
||||
private enum MapOperation {
|
||||
CREATE, UPDATE, DELETE,
|
||||
}
|
||||
|
||||
private boolean active;
|
||||
private boolean rollback;
|
||||
private final Map<K, MapTaskWithValue> tasks = new LinkedHashMap<>();
|
||||
private final MapStorage<K, V, M> map;
|
||||
|
||||
public MapKeycloakTransaction(MapStorage<K, V, M> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void begin() {
|
||||
active = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
log.tracef("Commit - %s", map);
|
||||
|
||||
if (rollback) {
|
||||
throw new RuntimeException("Rollback only!");
|
||||
}
|
||||
|
||||
for (MapTaskWithValue value : tasks.values()) {
|
||||
value.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
tasks.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
rollback = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRollbackOnly() {
|
||||
return rollback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
public interface MapKeycloakTransaction<K, V extends AbstractEntity<K>, M> extends KeycloakTransaction {
|
||||
|
||||
/**
|
||||
* Adds a given task if not exists for the given key
|
||||
*/
|
||||
protected void addTask(K key, MapTaskWithValue task) {
|
||||
log.tracef("Adding operation %s for %s @ %08x", task.getOperation(), key, System.identityHashCode(task.getValue()));
|
||||
|
||||
K taskKey = key;
|
||||
tasks.merge(taskKey, task, MapTaskCompose::new);
|
||||
}
|
||||
|
||||
// This is for possibility to lookup for session by id, which was created in this transaction
|
||||
public V read(K key) {
|
||||
try { // TODO: Consider using Optional rather than handling NPE
|
||||
return read(key, map::read);
|
||||
} catch (NullPointerException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public V read(K key, Function<K, V> defaultValueFunc) {
|
||||
MapTaskWithValue current = tasks.get(key);
|
||||
// If the key exists, then it has entered the "tasks" after bulk delete that could have
|
||||
// removed it, so looking through bulk deletes is irrelevant
|
||||
if (tasks.containsKey(key)) {
|
||||
return current.getValue();
|
||||
}
|
||||
|
||||
// If the key does not exist, then it would be read fresh from the storage, but then it
|
||||
// could have been removed by some bulk delete in the existing tasks. Check it.
|
||||
final V value = defaultValueFunc.apply(key);
|
||||
for (MapTaskWithValue val : tasks.values()) {
|
||||
if (val instanceof MapKeycloakTransaction.BulkDeleteOperation) {
|
||||
final BulkDeleteOperation delOp = (BulkDeleteOperation) val;
|
||||
if (! delOp.getFilterForNonDeletedObjects().test(value)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stream of records that match given criteria and includes changes made in this transaction, i.e.
|
||||
* the result contains updates and excludes records that have been deleted in this transaction.
|
||||
* Instructs this transaction to add a new value into the underlying store on commit.
|
||||
*
|
||||
* @param mcb
|
||||
* @return
|
||||
* @param key an identifier that will be associated with the {@code value}
|
||||
* @param value the value
|
||||
*/
|
||||
public Stream<V> getUpdatedNotRemoved(ModelCriteriaBuilder<M> mcb) {
|
||||
Predicate<? super V> filterOutAllBulkDeletedObjects = tasks.values().stream()
|
||||
.filter(BulkDeleteOperation.class::isInstance)
|
||||
.map(BulkDeleteOperation.class::cast)
|
||||
.map(BulkDeleteOperation::getFilterForNonDeletedObjects)
|
||||
.reduce(Predicate::and)
|
||||
.orElse(v -> true);
|
||||
|
||||
Stream<V> updatedAndNotRemovedObjectsStream = this.map.read(mcb)
|
||||
.filter(filterOutAllBulkDeletedObjects)
|
||||
.map(this::getUpdated) // If the object has been removed, tx.get will return null, otherwise it will return me.getValue()
|
||||
.filter(Objects::nonNull);
|
||||
|
||||
// In case of created values stored in MapKeycloakTransaction, we need filter those according to the filter
|
||||
MapModelCriteriaBuilder<K, V, M> mapMcb = mcb.unwrap(MapModelCriteriaBuilder.class);
|
||||
Stream<V> res = mapMcb == null
|
||||
? updatedAndNotRemovedObjectsStream
|
||||
: Stream.concat(
|
||||
createdValuesStream(mapMcb.getKeyFilter(), mapMcb.getEntityFilter()),
|
||||
updatedAndNotRemovedObjectsStream
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
void create(K key, V value);
|
||||
|
||||
/**
|
||||
* Returns the stream of records that match given criteria and includes changes made in this transaction, i.e.
|
||||
* the result contains updates and excludes records that have been deleted in this transaction.
|
||||
* Provides possibility to lookup for values by a {@code key} in the underlying store with respect to changes done
|
||||
* in current transaction.
|
||||
*
|
||||
* @param mcb
|
||||
* @return
|
||||
* @param key identifier of a value
|
||||
* @return a value associated with the given {@code key}
|
||||
*/
|
||||
public long getCount(ModelCriteriaBuilder<M> mcb) {
|
||||
return getUpdatedNotRemoved(mcb).count();
|
||||
}
|
||||
V read(K key);
|
||||
|
||||
/**
|
||||
* Returns a updated version of the {@code orig} object as updated in this transaction.
|
||||
* Looks up a value in the current transaction with corresponding key, returns {@code defaultValueFunc} when
|
||||
* the transaction does not contain a value for the {@code key} identifier.
|
||||
*
|
||||
* @param key identifier of a value
|
||||
* @param defaultValueFunc fallback function if the transaction does not contain a value that corresponds to {@code key}
|
||||
* @return a value associated with the given {@code key}, or the result of {@code defaultValueFunc}
|
||||
*
|
||||
*/
|
||||
V read(K key, Function<K, V> defaultValueFunc);
|
||||
|
||||
/**
|
||||
* Returns a stream of values from underlying storage that are updated based on the current transaction changes;
|
||||
* i.e. the result contains updates and excludes of records that have been created, updated or deleted in this
|
||||
* transaction by methods {@link MapKeycloakTransaction#create}, {@link MapKeycloakTransaction#update},
|
||||
* {@link MapKeycloakTransaction#delete}, etc.
|
||||
*
|
||||
* @param mcb criteria to filter values
|
||||
* @return values that fulfill the given criteria, that are updated based on changes in the current transaction
|
||||
*/
|
||||
Stream<V> read(ModelCriteriaBuilder<M> mcb);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a number of values present in the underlying storage that fulfill the given criteria with respect to
|
||||
* changes done in the current transaction.
|
||||
*
|
||||
* @param mcb criteria to filter values
|
||||
* @return number of values present in the storage that fulfill the given criteria
|
||||
*/
|
||||
long getCount(ModelCriteriaBuilder<M> mcb);
|
||||
|
||||
/**
|
||||
* Instructs this transaction to force-update the {@code value} associated with the identifier {@code key} in the
|
||||
* underlying store on commit.
|
||||
*
|
||||
* @param key identifier of the {@code value}
|
||||
* @param value updated version of the value
|
||||
*/
|
||||
void update(K key, V value);
|
||||
|
||||
/**
|
||||
* Returns an updated version of the {@code orig} object as updated in this transaction.
|
||||
*
|
||||
* If the underlying store handles transactions on its own, this can return {@code orig} directly.
|
||||
* @param orig
|
||||
* @return The {@code orig} object as visible from this transaction, or {@code null} if the object has been removed.
|
||||
*
|
||||
* @param orig possibly stale version of some object from the underlying store
|
||||
* @return the {@code orig} object as visible from this transaction, or {@code null} if the object has been removed.
|
||||
*/
|
||||
public V getUpdated(V orig) {
|
||||
MapTaskWithValue current = orig == null ? null : tasks.get(orig.getId());
|
||||
return current == null ? orig : current.getValue();
|
||||
}
|
||||
|
||||
public void update(K key, V value) {
|
||||
addTask(key, new UpdateOperation(key, value));
|
||||
}
|
||||
|
||||
public void create(K key, V value) {
|
||||
addTask(key, new CreateOperation(key, value));
|
||||
}
|
||||
|
||||
public void updateIfChanged(K key, V value, Predicate<V> shouldPut) {
|
||||
log.tracef("Adding operation UPDATE_IF_CHANGED for %s @ %08x", key, System.identityHashCode(value));
|
||||
|
||||
K taskKey = key;
|
||||
MapTaskWithValue op = new MapTaskWithValue(value) {
|
||||
@Override
|
||||
public void execute() {
|
||||
if (shouldPut.test(getValue())) {
|
||||
map.update(key, getValue());
|
||||
}
|
||||
}
|
||||
@Override public MapOperation getOperation() { return MapOperation.UPDATE; }
|
||||
};
|
||||
tasks.merge(taskKey, op, this::merge);
|
||||
}
|
||||
|
||||
public void delete(K key) {
|
||||
addTask(key, new DeleteOperation(key));
|
||||
default V getUpdated(V orig) {
|
||||
return orig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk removal of items.
|
||||
* Instructs this transaction to update the {@code value} associated with the identifier {@code key} in the
|
||||
* underlying store on commit, if by the time of {@code commit} the {@code shouldPut} predicate returns {@code true}
|
||||
*
|
||||
* @param artificialKey Key to record the transaction with, must be a key that does not exist in this transaction to
|
||||
* prevent collision with other operations in this transaction
|
||||
* @param mcb
|
||||
* @param key identifier of the {@code value}
|
||||
* @param value new version of the value
|
||||
* @param shouldPut predicate to check in commit phase
|
||||
*/
|
||||
public long delete(K artificialKey, ModelCriteriaBuilder<M> mcb) {
|
||||
log.tracef("Adding operation DELETE_BULK");
|
||||
void updateIfChanged(K key, V value, Predicate<V> shouldPut);
|
||||
|
||||
/**
|
||||
* Instructs this transaction to delete a value associated with the identifier {@code key} from the underlying store
|
||||
* on commit.
|
||||
*
|
||||
* @param key identifier of a value
|
||||
*/
|
||||
void delete(K key);
|
||||
|
||||
/**
|
||||
* Instructs this transaction to remove values (identified by {@code mcb} filter) from the underlying store on commit.
|
||||
*
|
||||
* @param artificialKey key to record the transaction with, must be a key that does not exist in this transaction to
|
||||
* prevent collisions with other operations in this transaction
|
||||
* @param mcb criteria to delete values
|
||||
*/
|
||||
long delete(K artificialKey, ModelCriteriaBuilder<M> mcb);
|
||||
|
||||
// Remove all tasks that create / update / delete objects deleted by the bulk removal.
|
||||
final BulkDeleteOperation bdo = new BulkDeleteOperation(mcb);
|
||||
Predicate<V> filterForNonDeletedObjects = bdo.getFilterForNonDeletedObjects();
|
||||
long res = 0;
|
||||
for (Iterator<Entry<K, MapTaskWithValue>> it = tasks.entrySet().iterator(); it.hasNext();) {
|
||||
Entry<K, MapTaskWithValue> me = it.next();
|
||||
if (! filterForNonDeletedObjects.test(me.getValue().getValue())) {
|
||||
log.tracef(" [DELETE_BULK] removing %s", me.getKey());
|
||||
it.remove();
|
||||
res++;
|
||||
}
|
||||
}
|
||||
|
||||
tasks.put(artificialKey, bdo);
|
||||
|
||||
return res + bdo.getCount();
|
||||
}
|
||||
|
||||
private Stream<V> createdValuesStream(Predicate<? super K> keyFilter, Predicate<? super V> entityFilter) {
|
||||
return this.tasks.entrySet().stream()
|
||||
.filter(me -> keyFilter.test(me.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.filter(v -> v.containsCreate() && ! v.isReplace())
|
||||
.map(MapTaskWithValue::getValue)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(entityFilter)
|
||||
// make a snapshot
|
||||
.collect(Collectors.toList()).stream();
|
||||
}
|
||||
|
||||
private MapTaskWithValue merge(MapTaskWithValue oldValue, MapTaskWithValue newValue) {
|
||||
switch (newValue.getOperation()) {
|
||||
case DELETE:
|
||||
return oldValue.containsCreate() ? null : newValue;
|
||||
default:
|
||||
return new MapTaskCompose(oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract class MapTaskWithValue {
|
||||
protected final V value;
|
||||
|
||||
public MapTaskWithValue(V value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean containsCreate() {
|
||||
return MapOperation.CREATE == getOperation();
|
||||
}
|
||||
|
||||
public boolean containsRemove() {
|
||||
return MapOperation.DELETE == getOperation();
|
||||
}
|
||||
|
||||
public boolean isReplace() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract MapOperation getOperation();
|
||||
public abstract void execute();
|
||||
}
|
||||
|
||||
private class MapTaskCompose extends MapTaskWithValue {
|
||||
|
||||
private final MapTaskWithValue oldValue;
|
||||
private final MapTaskWithValue newValue;
|
||||
|
||||
public MapTaskCompose(MapTaskWithValue oldValue, MapTaskWithValue newValue) {
|
||||
super(null);
|
||||
this.oldValue = oldValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
oldValue.execute();
|
||||
newValue.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return newValue.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapOperation getOperation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsCreate() {
|
||||
return oldValue.containsCreate() || newValue.containsCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRemove() {
|
||||
return oldValue.containsRemove() || newValue.containsRemove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplace() {
|
||||
return (newValue.getOperation() == MapOperation.CREATE && oldValue.containsRemove()) ||
|
||||
(oldValue instanceof MapKeycloakTransaction.MapTaskCompose && ((MapTaskCompose) oldValue).isReplace());
|
||||
}
|
||||
}
|
||||
|
||||
private class CreateOperation extends MapTaskWithValue {
|
||||
private final K key;
|
||||
|
||||
public CreateOperation(K key, V value) {
|
||||
super(value);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override public void execute() { map.create(key, getValue()); }
|
||||
@Override public MapOperation getOperation() { return MapOperation.CREATE; }
|
||||
}
|
||||
|
||||
private class UpdateOperation extends MapTaskWithValue {
|
||||
private final K key;
|
||||
|
||||
public UpdateOperation(K key, V value) {
|
||||
super(value);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override public void execute() { map.update(key, getValue()); }
|
||||
@Override public MapOperation getOperation() { return MapOperation.UPDATE; }
|
||||
}
|
||||
|
||||
private class DeleteOperation extends MapTaskWithValue {
|
||||
private final K key;
|
||||
|
||||
public DeleteOperation(K key) {
|
||||
super(null);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override public void execute() { map.delete(key); }
|
||||
@Override public MapOperation getOperation() { return MapOperation.DELETE; }
|
||||
}
|
||||
|
||||
private class BulkDeleteOperation extends MapTaskWithValue {
|
||||
|
||||
private final ModelCriteriaBuilder<M> mcb;
|
||||
|
||||
public BulkDeleteOperation(ModelCriteriaBuilder<M> mcb) {
|
||||
super(null);
|
||||
this.mcb = mcb;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute() {
|
||||
map.delete(mcb);
|
||||
}
|
||||
|
||||
public Predicate<V> getFilterForNonDeletedObjects() {
|
||||
if (! (mcb instanceof MapModelCriteriaBuilder)) {
|
||||
return t -> true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final MapModelCriteriaBuilder<K, V, M> mmcb = (MapModelCriteriaBuilder<K, V, M>) mcb;
|
||||
|
||||
Predicate<? super V> entityFilter = mmcb.getEntityFilter();
|
||||
Predicate<? super K> keyFilter = ((MapModelCriteriaBuilder) mcb).getKeyFilter();
|
||||
return v -> v == null || ! (keyFilter.test(v.getId()) && entityFilter.test(v));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapOperation getOperation() {
|
||||
return MapOperation.DELETE;
|
||||
}
|
||||
|
||||
private long getCount() {
|
||||
return map.getCount(mcb);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* Copyright 2020 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.map.storage.chm;
|
||||
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
|
||||
public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>, M> implements MapKeycloakTransaction<K, V, M> {
|
||||
|
||||
private final static Logger log = Logger.getLogger(ConcurrentHashMapKeycloakTransaction.class);
|
||||
|
||||
private boolean active;
|
||||
private boolean rollback;
|
||||
private final Map<K, MapTaskWithValue> tasks = new LinkedHashMap<>();
|
||||
private final MapStorage<K, V, M> map;
|
||||
|
||||
enum MapOperation {
|
||||
CREATE, UPDATE, DELETE,
|
||||
}
|
||||
|
||||
public ConcurrentHashMapKeycloakTransaction(MapStorage<K, V, M> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void begin() {
|
||||
active = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
log.tracef("Commit - %s", map);
|
||||
|
||||
if (rollback) {
|
||||
throw new RuntimeException("Rollback only!");
|
||||
}
|
||||
|
||||
for (MapTaskWithValue value : tasks.values()) {
|
||||
value.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
tasks.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
rollback = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRollbackOnly() {
|
||||
return rollback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a given task if not exists for the given key
|
||||
*/
|
||||
protected void addTask(K key, MapTaskWithValue task) {
|
||||
log.tracef("Adding operation %s for %s @ %08x", task.getOperation(), key, System.identityHashCode(task.getValue()));
|
||||
|
||||
K taskKey = key;
|
||||
tasks.merge(taskKey, task, MapTaskCompose::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V read(K key) {
|
||||
try { // TODO: Consider using Optional rather than handling NPE
|
||||
return read(key, map::read);
|
||||
} catch (NullPointerException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V read(K key, Function<K, V> defaultValueFunc) {
|
||||
MapTaskWithValue current = tasks.get(key);
|
||||
// If the key exists, then it has entered the "tasks" after bulk delete that could have
|
||||
// removed it, so looking through bulk deletes is irrelevant
|
||||
if (tasks.containsKey(key)) {
|
||||
return current.getValue();
|
||||
}
|
||||
|
||||
// If the key does not exist, then it would be read fresh from the storage, but then it
|
||||
// could have been removed by some bulk delete in the existing tasks. Check it.
|
||||
final V value = defaultValueFunc.apply(key);
|
||||
for (MapTaskWithValue val : tasks.values()) {
|
||||
if (val instanceof ConcurrentHashMapKeycloakTransaction.BulkDeleteOperation) {
|
||||
final BulkDeleteOperation delOp = (BulkDeleteOperation) val;
|
||||
if (! delOp.getFilterForNonDeletedObjects().test(value)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stream of records that match given criteria and includes changes made in this transaction, i.e.
|
||||
* the result contains updates and excludes records that have been deleted in this transaction.
|
||||
*
|
||||
* @param mcb
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Stream<V> read(ModelCriteriaBuilder<M> mcb) {
|
||||
Predicate<? super V> filterOutAllBulkDeletedObjects = tasks.values().stream()
|
||||
.filter(BulkDeleteOperation.class::isInstance)
|
||||
.map(BulkDeleteOperation.class::cast)
|
||||
.map(BulkDeleteOperation::getFilterForNonDeletedObjects)
|
||||
.reduce(Predicate::and)
|
||||
.orElse(v -> true);
|
||||
|
||||
Stream<V> updatedAndNotRemovedObjectsStream = this.map.read(mcb)
|
||||
.filter(filterOutAllBulkDeletedObjects)
|
||||
.map(this::getUpdated) // If the object has been removed, tx.get will return null, otherwise it will return me.getValue()
|
||||
.filter(Objects::nonNull);
|
||||
|
||||
// In case of created values stored in MapKeycloakTransaction, we need filter those according to the filter
|
||||
MapModelCriteriaBuilder<K, V, M> mapMcb = mcb.unwrap(MapModelCriteriaBuilder.class);
|
||||
Stream<V> res = mapMcb == null
|
||||
? updatedAndNotRemovedObjectsStream
|
||||
: Stream.concat(
|
||||
createdValuesStream(mapMcb.getKeyFilter(), mapMcb.getEntityFilter()),
|
||||
updatedAndNotRemovedObjectsStream
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount(ModelCriteriaBuilder<M> mcb) {
|
||||
return read(mcb).count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getUpdated(V orig) {
|
||||
MapTaskWithValue current = orig == null ? null : tasks.get(orig.getId());
|
||||
return current == null ? orig : current.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(K key, V value) {
|
||||
addTask(key, new UpdateOperation(key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(K key, V value) {
|
||||
addTask(key, new CreateOperation(key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIfChanged(K key, V value, Predicate<V> shouldPut) {
|
||||
log.tracef("Adding operation UPDATE_IF_CHANGED for %s @ %08x", key, System.identityHashCode(value));
|
||||
|
||||
K taskKey = key;
|
||||
MapTaskWithValue op = new MapTaskWithValue(value) {
|
||||
@Override
|
||||
public void execute() {
|
||||
if (shouldPut.test(getValue())) {
|
||||
map.update(key, getValue());
|
||||
}
|
||||
}
|
||||
@Override public MapOperation getOperation() { return MapOperation.UPDATE; }
|
||||
};
|
||||
tasks.merge(taskKey, op, this::merge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(K key) {
|
||||
addTask(key, new DeleteOperation(key));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long delete(K artificialKey, ModelCriteriaBuilder<M> mcb) {
|
||||
log.tracef("Adding operation DELETE_BULK");
|
||||
|
||||
// Remove all tasks that create / update / delete objects deleted by the bulk removal.
|
||||
final BulkDeleteOperation bdo = new BulkDeleteOperation(mcb);
|
||||
Predicate<V> filterForNonDeletedObjects = bdo.getFilterForNonDeletedObjects();
|
||||
long res = 0;
|
||||
for (Iterator<Entry<K, MapTaskWithValue>> it = tasks.entrySet().iterator(); it.hasNext();) {
|
||||
Entry<K, MapTaskWithValue> me = it.next();
|
||||
if (! filterForNonDeletedObjects.test(me.getValue().getValue())) {
|
||||
log.tracef(" [DELETE_BULK] removing %s", me.getKey());
|
||||
it.remove();
|
||||
res++;
|
||||
}
|
||||
}
|
||||
|
||||
tasks.put(artificialKey, bdo);
|
||||
|
||||
return res + bdo.getCount();
|
||||
}
|
||||
|
||||
private Stream<V> createdValuesStream(Predicate<? super K> keyFilter, Predicate<? super V> entityFilter) {
|
||||
return this.tasks.entrySet().stream()
|
||||
.filter(me -> keyFilter.test(me.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.filter(v -> v.containsCreate() && ! v.isReplace())
|
||||
.map(MapTaskWithValue::getValue)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(entityFilter)
|
||||
// make a snapshot
|
||||
.collect(Collectors.toList()).stream();
|
||||
}
|
||||
|
||||
private MapTaskWithValue merge(MapTaskWithValue oldValue, MapTaskWithValue newValue) {
|
||||
switch (newValue.getOperation()) {
|
||||
case DELETE:
|
||||
return oldValue.containsCreate() ? null : newValue;
|
||||
default:
|
||||
return new MapTaskCompose(oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract class MapTaskWithValue {
|
||||
protected final V value;
|
||||
|
||||
public MapTaskWithValue(V value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean containsCreate() {
|
||||
return MapOperation.CREATE == getOperation();
|
||||
}
|
||||
|
||||
public boolean containsRemove() {
|
||||
return MapOperation.DELETE == getOperation();
|
||||
}
|
||||
|
||||
public boolean isReplace() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract MapOperation getOperation();
|
||||
public abstract void execute();
|
||||
}
|
||||
|
||||
private class MapTaskCompose extends MapTaskWithValue {
|
||||
|
||||
private final MapTaskWithValue oldValue;
|
||||
private final MapTaskWithValue newValue;
|
||||
|
||||
public MapTaskCompose(MapTaskWithValue oldValue, MapTaskWithValue newValue) {
|
||||
super(null);
|
||||
this.oldValue = oldValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
oldValue.execute();
|
||||
newValue.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return newValue.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapOperation getOperation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsCreate() {
|
||||
return oldValue.containsCreate() || newValue.containsCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRemove() {
|
||||
return oldValue.containsRemove() || newValue.containsRemove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplace() {
|
||||
return (newValue.getOperation() == MapOperation.CREATE && oldValue.containsRemove()) ||
|
||||
(oldValue instanceof ConcurrentHashMapKeycloakTransaction.MapTaskCompose && ((MapTaskCompose) oldValue).isReplace());
|
||||
}
|
||||
}
|
||||
|
||||
private class CreateOperation extends MapTaskWithValue {
|
||||
private final K key;
|
||||
|
||||
public CreateOperation(K key, V value) {
|
||||
super(value);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override public void execute() { map.create(key, getValue()); }
|
||||
@Override public MapOperation getOperation() { return MapOperation.CREATE; }
|
||||
}
|
||||
|
||||
private class UpdateOperation extends MapTaskWithValue {
|
||||
private final K key;
|
||||
|
||||
public UpdateOperation(K key, V value) {
|
||||
super(value);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override public void execute() { map.update(key, getValue()); }
|
||||
@Override public MapOperation getOperation() { return MapOperation.UPDATE; }
|
||||
}
|
||||
|
||||
private class DeleteOperation extends MapTaskWithValue {
|
||||
private final K key;
|
||||
|
||||
public DeleteOperation(K key) {
|
||||
super(null);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override public void execute() { map.delete(key); }
|
||||
@Override public MapOperation getOperation() { return MapOperation.DELETE; }
|
||||
}
|
||||
|
||||
private class BulkDeleteOperation extends MapTaskWithValue {
|
||||
|
||||
private final ModelCriteriaBuilder<M> mcb;
|
||||
|
||||
public BulkDeleteOperation(ModelCriteriaBuilder<M> mcb) {
|
||||
super(null);
|
||||
this.mcb = mcb;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute() {
|
||||
map.delete(mcb);
|
||||
}
|
||||
|
||||
public Predicate<V> getFilterForNonDeletedObjects() {
|
||||
if (! (mcb instanceof MapModelCriteriaBuilder)) {
|
||||
return t -> true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final MapModelCriteriaBuilder<K, V, M> mmcb = (MapModelCriteriaBuilder<K, V, M>) mcb;
|
||||
|
||||
Predicate<? super V> entityFilter = mmcb.getEntityFilter();
|
||||
Predicate<? super K> keyFilter = ((MapModelCriteriaBuilder) mcb).getKeyFilter();
|
||||
return v -> v == null || ! (keyFilter.test(v.getId()) && entityFilter.test(v));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapOperation getOperation() {
|
||||
return MapOperation.DELETE;
|
||||
}
|
||||
|
||||
private long getCount() {
|
||||
return map.getCount(mcb);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,10 +17,10 @@
|
|||
package org.keycloak.models.map.storage.chm;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.storage.MapFieldPredicates;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
@ -107,8 +107,8 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K>, M> impleme
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public MapKeycloakTransaction<K, V, M> createTransaction(KeycloakSession session) {
|
||||
MapKeycloakTransaction sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
|
||||
return sessionTransaction == null ? new MapKeycloakTransaction<>(this) : (MapKeycloakTransaction<K, V, M>) sessionTransaction;
|
||||
MapKeycloakTransaction<K, V, M> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
|
||||
return sessionTransaction == null ? new ConcurrentHashMapKeycloakTransaction<>(this) : sessionTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -39,7 +39,7 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
|
|||
|
||||
private final ConcurrentHashMapStorage<K, MapAuthenticatedClientSessionEntity<K>, AuthenticatedClientSessionModel> clientSessionStore;
|
||||
|
||||
private class Transaction extends MapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel> {
|
||||
private class Transaction extends ConcurrentHashMapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel> {
|
||||
|
||||
private final MapKeycloakTransaction<K, MapAuthenticatedClientSessionEntity<K>, AuthenticatedClientSessionModel> clientSessionTr;
|
||||
|
||||
|
@ -50,7 +50,7 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
|
|||
|
||||
@Override
|
||||
public long delete(K artificialKey, ModelCriteriaBuilder<UserSessionModel> mcb) {
|
||||
Set<K> ids = getUpdatedNotRemoved(mcb).map(AbstractEntity::getId).collect(Collectors.toSet());
|
||||
Set<K> ids = read(mcb).map(AbstractEntity::getId).collect(Collectors.toSet());
|
||||
ModelCriteriaBuilder<AuthenticatedClientSessionModel> csMcb = clientSessionStore.createCriteriaBuilder().compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.IN, ids);
|
||||
clientSessionTr.delete(artificialKey, csMcb);
|
||||
return super.delete(artificialKey, mcb);
|
||||
|
@ -75,7 +75,7 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public MapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel> createTransaction(KeycloakSession session) {
|
||||
MapKeycloakTransaction sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
|
||||
return sessionTransaction == null ? new Transaction(clientSessionStore.createTransaction(session)) : (MapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel>) sessionTransaction;
|
||||
MapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
|
||||
return sessionTransaction == null ? new Transaction(clientSessionStore.createTransaction(session)) : sessionTransaction;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.IDP_AND_USER, Operator.EQ, socialProvider);
|
||||
|
||||
tx.getUpdatedNotRemoved(mcb)
|
||||
tx.read(mcb)
|
||||
.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeFederatedIdentity(socialProvider));
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.IDP_AND_USER, Operator.EQ, socialLink.getIdentityProvider(), socialLink.getUserId());
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.collect(Collectors.collectingAndThen(
|
||||
Collectors.toList(),
|
||||
list -> {
|
||||
|
@ -298,7 +298,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, client.getRealm().getId())
|
||||
.compare(SearchableFields.SERVICE_ACCOUNT_CLIENT, Operator.EQ, client.getId());
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.collect(Collectors.collectingAndThen(
|
||||
Collectors.toList(),
|
||||
list -> {
|
||||
|
@ -382,7 +382,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.FEDERATION_LINK, Operator.EQ, storageProviderId);
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.setFederationLink(null));
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.ASSIGNED_ROLE, Operator.EQ, roleId);
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeRolesMembership(roleId));
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.ASSIGNED_GROUP, Operator.EQ, groupId);
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeGroupsMembership(groupId));
|
||||
}
|
||||
|
@ -424,7 +424,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.CONSENT_FOR_CLIENT, Operator.EQ, clientId);
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeUserConsent(clientId));
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, clientScope.getRealm().getId())
|
||||
.compare(SearchableFields.CONSENT_WITH_CLIENT_SCOPE, Operator.EQ, clientScopeId);
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
s.flatMap(MapUserEntity::getUserConsents)
|
||||
.forEach(consent -> consent.removeGrantedClientScopesIds(clientScopeId));
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.CONSENT_CLIENT_FEDERATION_LINK, Operator.EQ, componentId);
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
String providerIdS = new StorageId(componentId, "").getId();
|
||||
s.forEach(removeConsentsForExternalClient(providerIdS));
|
||||
}
|
||||
|
@ -490,7 +490,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
ModelCriteriaBuilder<UserModel> mcb = userStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(entity -> entity.addRolesMembership(roleId));
|
||||
}
|
||||
|
@ -510,7 +510,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.USERNAME, Operator.ILIKE, username);
|
||||
|
||||
try (Stream<MapUserEntity<K>> s = tx.getUpdatedNotRemoved(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(mcb)) {
|
||||
return s.findFirst()
|
||||
.map(entityToAdapterFunc(realm)).orElse(null);
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.EMAIL, Operator.EQ, email);
|
||||
|
||||
List<MapUserEntity<K>> usersWithEmail = tx.getUpdatedNotRemoved(mcb)
|
||||
List<MapUserEntity<K>> usersWithEmail = tx.read(mcb)
|
||||
.filter(userEntity -> Objects.equals(userEntity.getEmail(), email))
|
||||
.collect(Collectors.toList());
|
||||
if (usersWithEmail.isEmpty()) return null;
|
||||
|
@ -584,7 +584,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
mcb = mcb.compare(SearchableFields.SERVICE_ACCOUNT_CLIENT, Operator.NOT_EXISTS);
|
||||
}
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME), firstResult, maxResults)
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
@ -701,7 +701,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
mcb = mcb.compare(SearchableFields.ASSIGNED_GROUP, Operator.IN, authorizedGroups);
|
||||
}
|
||||
|
||||
Stream<MapUserEntity<K>> usersStream = tx.getUpdatedNotRemoved(mcb)
|
||||
Stream<MapUserEntity<K>> usersStream = tx.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME); // Sort before paginating
|
||||
|
||||
return paginatedStream(usersStream, firstResult, maxResults) // paginate if necessary
|
||||
|
@ -716,7 +716,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.ASSIGNED_GROUP, Operator.EQ, group.getId());
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb).sorted(MapUserEntity.COMPARE_BY_USERNAME), firstResult, maxResults)
|
||||
return paginatedStream(tx.read(mcb).sorted(MapUserEntity.COMPARE_BY_USERNAME), firstResult, maxResults)
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
|
@ -727,7 +727,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.ATTRIBUTE, Operator.EQ, attrName, attrValue);
|
||||
|
||||
return tx.getUpdatedNotRemoved(mcb)
|
||||
return tx.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME)
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
@ -756,7 +756,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.ASSIGNED_ROLE, Operator.EQ, role.getId());
|
||||
|
||||
return paginatedStream(tx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME), firstResult, maxResults)
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
.compare(AuthenticatedClientSessionModel.SearchableFields.CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, client.getId())
|
||||
.compare(AuthenticatedClientSessionModel.SearchableFields.IS_OFFLINE, ModelCriteriaBuilder.Operator.EQ, offline);
|
||||
|
||||
return clientSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return clientSessionTx.read(mcb)
|
||||
.findFirst()
|
||||
.map(clientEntityToAdapterFunc(client.getRealm(), client, userSession))
|
||||
.orElse(null);
|
||||
|
@ -258,7 +258,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
ModelCriteriaBuilder<UserSessionModel> mcb = realmAndOfflineCriteriaBuilder(realm, false)
|
||||
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uuid);
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.findFirst()
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -271,7 +271,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionsStream(%s, %s)%s", realm, user, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionsStream(%s, %s)%s", realm, client, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionByBrokerUserIdStream(%s, %s)%s", realm, brokerUserId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionByBrokerSessionId(%s, %s)%s", realm, brokerSessionId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.findFirst()
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -356,7 +356,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getActiveClientSessionStats(%s, %s)%s", realm, offline, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull)
|
||||
.map(UserSessionModel::getAuthenticatedClientSessions)
|
||||
|
@ -496,7 +496,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionsStream(%s, %s)%s", realm, user, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -508,7 +508,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionByBrokerSessionId(%s, %s)%s", realm, brokerSessionId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.findFirst()
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -521,7 +521,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionByBrokerUserIdStream(%s, %s)%s", realm, brokerUserId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return userSessionTx.read(mcb)
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionsStream(%s, %s, %s, %s)%s", realm, client, firstResult, maxResults, getShortStackTrace());
|
||||
|
||||
return paginatedStream(userSessionTx.getUpdatedNotRemoved(mcb)
|
||||
return paginatedStream(userSessionTx.read(mcb)
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(Comparator.comparing(UserSessionModel::getLastSessionRefresh)), firstResult, maxResults);
|
||||
|
@ -595,7 +595,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uuid);
|
||||
|
||||
// check if it's an offline user session
|
||||
MapUserSessionEntity<UK> userSessionEntity = userSessionTx.getUpdatedNotRemoved(mcb).findFirst().orElse(null);
|
||||
MapUserSessionEntity<UK> userSessionEntity = userSessionTx.read(mcb).findFirst().orElse(null);
|
||||
if (userSessionEntity != null) {
|
||||
if (userSessionEntity.isOffline()) {
|
||||
return Stream.of(userSessionEntity);
|
||||
|
@ -604,7 +604,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
// no session found by the given ID, try to find by corresponding session ID
|
||||
mcb = realmAndOfflineCriteriaBuilder(realm, true)
|
||||
.compare(UserSessionModel.SearchableFields.CORRESPONDING_SESSION_ID, ModelCriteriaBuilder.Operator.EQ, userSessionId);
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb);
|
||||
return userSessionTx.read(mcb);
|
||||
}
|
||||
|
||||
// it's online user session so lookup offline user session by corresponding session id reference
|
||||
|
@ -613,7 +613,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
UK uk = userSessionStore.getKeyConvertor().fromStringSafe(offlineUserSessionId);
|
||||
mcb = realmAndOfflineCriteriaBuilder(realm, true)
|
||||
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uk);
|
||||
return userSessionTx.getUpdatedNotRemoved(mcb);
|
||||
return userSessionTx.read(mcb);
|
||||
}
|
||||
|
||||
return Stream.empty();
|
||||
|
|
Loading…
Reference in a new issue