KEYCLOAK-18370 Introduce QueryParameters
This commit is contained in:
parent
7d26b245de
commit
dc1c9b944f
26 changed files with 520 additions and 352 deletions
|
@ -40,6 +40,7 @@ import java.util.function.Predicate;
|
|||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
||||
|
@ -144,7 +145,7 @@ public class MapRootAuthenticationSessionProvider<K> implements AuthenticationSe
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.TIMESTAMP, Operator.LT, expired);
|
||||
|
||||
long deletedCount = tx.delete(sessionStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
long deletedCount = tx.delete(sessionStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
|
||||
LOG.debugf("Removed %d expired authentication sessions for realm '%s'", deletedCount, realm.getName());
|
||||
}
|
||||
|
@ -155,7 +156,7 @@ public class MapRootAuthenticationSessionProvider<K> implements AuthenticationSe
|
|||
ModelCriteriaBuilder<RootAuthenticationSessionModel> mcb = sessionStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
sessionStore.delete(mcb);
|
||||
sessionStore.delete(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
|||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -45,6 +44,8 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
import static org.keycloak.utils.StreamsUtil.distinctByKey;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
|
||||
|
@ -90,7 +91,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
.toArray(ModelCriteriaBuilder[]::new)
|
||||
);
|
||||
|
||||
return tx.getCount(mcb);
|
||||
return tx.getCount(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,7 +110,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
mcb = mcb.compare(SearchableFields.SCOPE_ID, Operator.EQ, scopeId);
|
||||
}
|
||||
|
||||
if (tx.getCount(mcb) > 0) {
|
||||
if (tx.getCount(withCriteria(mcb)) > 0) {
|
||||
throw new ModelDuplicateException("Permission ticket for resource server: '" + resourceServer.getId()
|
||||
+ ", Resource: " + resourceId + ", owner: " + owner + ", scopeId: " + scopeId + " already exists.");
|
||||
}
|
||||
|
@ -142,8 +143,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(PermissionTicket.SearchableFields.ID, Operator.EQ, id))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.orElse(null);
|
||||
|
@ -153,7 +154,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.read(forResourceServer(resourceServerId))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -162,8 +163,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, owner))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, owner)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -172,8 +173,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.RESOURCE_ID, Operator.EQ, resourceId))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.RESOURCE_ID, Operator.EQ, resourceId)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -182,8 +183,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.EQ, scopeId))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.EQ, scopeId)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -212,9 +213,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
.toArray(ModelCriteriaBuilder[]::new)
|
||||
);
|
||||
|
||||
Comparator<? super MapPermissionTicketEntity<K>> c = Comparator.comparing(MapPermissionTicketEntity::getId);
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(c), firstResult, maxResult)
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResult, SearchableFields.ID))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -297,9 +296,8 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
.findById(ticket.getResourceId(), ticket.getResourceServerId());
|
||||
}
|
||||
|
||||
return paginatedStream(tx.read(mcb)
|
||||
return paginatedStream(tx.read(withCriteria(mcb).orderBy(SearchableFields.RESOURCE_ID, ASCENDING))
|
||||
.filter(distinctByKey(MapPermissionTicketEntity::getResourceId))
|
||||
.sorted(MapPermissionTicketEntity.COMPARE_BY_RESOURCE_ID)
|
||||
.map(ticketResourceMapper)
|
||||
.filter(Objects::nonNull), first, max)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -310,9 +308,8 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
|
|||
ModelCriteriaBuilder<PermissionTicket> mcb = permissionTicketStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, owner);
|
||||
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.filter(distinctByKey(MapPermissionTicketEntity::getResourceId))
|
||||
.sorted(MapPermissionTicketEntity.COMPARE_BY_RESOURCE_ID), first, max)
|
||||
return paginatedStream(tx.read(withCriteria(mcb).orderBy(SearchableFields.RESOURCE_ID, ASCENDING))
|
||||
.filter(distinctByKey(MapPermissionTicketEntity::getResourceId)), first, max)
|
||||
.map(ticket -> authorizationProvider.getStoreFactory().getResourceStore()
|
||||
.findById(ticket.getResourceId(), ticket.getResourceServerId()))
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -42,7 +42,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class MapPolicyStore<K> implements PolicyStore {
|
||||
|
||||
|
@ -86,7 +86,7 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
ModelCriteriaBuilder<Policy> mcb = forResourceServer(resourceServer.getId())
|
||||
.compare(SearchableFields.NAME, Operator.EQ, representation.getName());
|
||||
|
||||
if (tx.getCount(mcb) > 0) {
|
||||
if (tx.getCount(withCriteria(mcb)) > 0) {
|
||||
throw new ModelDuplicateException("Policy with name '" + representation.getName() + "' for " + resourceServer.getId() + " already exists");
|
||||
}
|
||||
|
||||
|
@ -111,8 +111,8 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
public Policy findById(String id, String resourceServerId) {
|
||||
LOG.tracef("findById(%s, %s)%s", id, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.orElse(null);
|
||||
|
@ -122,8 +122,8 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
public Policy findByName(String name, String resourceServerId) {
|
||||
LOG.tracef("findByName(%s, %s)%s", name, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.orElse(null);
|
||||
|
@ -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.read(forResourceServer(id))
|
||||
return tx.read(withCriteria(forResourceServer(id)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -153,11 +153,11 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
mcb = mcb.compare(SearchableFields.OWNER, Operator.NOT_EXISTS);
|
||||
}
|
||||
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(MapPolicyEntity.COMPARE_BY_NAME), firstResult, maxResult)
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResult, SearchableFields.NAME))
|
||||
.map(MapPolicyEntity<K>::getId)
|
||||
.map(K::toString)
|
||||
.map(id -> authorizationProvider.getStoreFactory().getPolicyStore().findById(id, resourceServerId)) // We need to go through cache
|
||||
.map(policyStore.getKeyConvertor()::keyToString)
|
||||
// We need to go through cache
|
||||
.map(id -> authorizationProvider.getStoreFactory().getPolicyStore().findById(id, resourceServerId))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -205,24 +205,24 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(Policy.SearchableFields.RESOURCE_ID, Operator.EQ, resourceId))
|
||||
tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.RESOURCE_ID, Operator.EQ, resourceId)))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findByResourceType(String type, String resourceServerId, Consumer<Policy> policyConsumer) {
|
||||
tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.CONFIG, Operator.LIKE, (Object[]) new String[] {"defaultResourceType", type}))
|
||||
tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.CONFIG, Operator.LIKE, (Object[]) new String[]{"defaultResourceType", type})))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(policyConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopeIds))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopeIds)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -241,21 +241,21 @@ public class MapPolicyStore<K> implements PolicyStore {
|
|||
.compare(SearchableFields.CONFIG, Operator.NOT_EXISTS, (Object[]) new String[] {"defaultResourceType"});
|
||||
}
|
||||
|
||||
tx.read(mcb).map(this::entityToAdapter).forEach(consumer);
|
||||
tx.read(withCriteria(mcb)).map(this::entityToAdapter).forEach(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByType(String type, String resourceServerId) {
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findDependentPolicies(String id, String resourceServerId) {
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ASSOCIATED_POLICY_ID, Operator.EQ, id))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ASSOCIATED_POLICY_ID, Operator.EQ, id)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
|||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -42,7 +41,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class MapResourceStore<K extends Comparable<K>> implements ResourceStore {
|
||||
|
||||
|
@ -86,7 +85,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
.compare(SearchableFields.NAME, Operator.EQ, name)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, owner);
|
||||
|
||||
if (tx.getCount(mcb) > 0) {
|
||||
if (tx.getCount(withCriteria(mcb)) > 0) {
|
||||
throw new ModelDuplicateException("Resource with name '" + name + "' for " + resourceServer.getId() + " already exists for request owner " + owner);
|
||||
}
|
||||
|
||||
|
@ -113,8 +112,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.orElse(null);
|
||||
|
@ -127,11 +126,10 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, ownerId))
|
||||
.sorted(c), firstResult, maxResult)
|
||||
.map(this::entityToAdapter)
|
||||
|
||||
tx.read(withCriteria(forResourceServer(resourceServerId).compare(SearchableFields.OWNER, Operator.EQ, ownerId))
|
||||
.pagination(firstResult, maxResult, SearchableFields.ID)
|
||||
).map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
|
@ -148,8 +146,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.URI, Operator.EQ, uri))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.URI, Operator.EQ, uri)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -158,7 +156,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.read(forResourceServer(resourceServerId))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -172,8 +170,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
.toArray(ModelCriteriaBuilder[]::new)
|
||||
);
|
||||
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(MapResourceEntity.COMPARE_BY_NAME), firstResult, maxResult)
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResult, SearchableFields.NAME))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -210,8 +207,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopes))
|
||||
tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopes)))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
@ -224,9 +221,9 @@ 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.read(forResourceServer(resourceServerId)
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, ownerId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name))
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.orElse(null);
|
||||
|
@ -235,8 +232,8 @@ 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.read(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type))
|
||||
tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type)))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
@ -252,7 +249,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
|
|||
mcb = mcb.compare(SearchableFields.OWNER, Operator.EQ, owner);
|
||||
}
|
||||
|
||||
tx.read(mcb)
|
||||
tx.read(withCriteria(mcb))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
@ -260,9 +257,9 @@ 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.read(forResourceServer(resourceServerId)
|
||||
tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.OWNER, Operator.NE, resourceServerId)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type))
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type)))
|
||||
.map(this::entityToAdapter)
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class MapScopeStore<K> implements ScopeStore {
|
||||
|
||||
|
@ -84,7 +84,7 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
ModelCriteriaBuilder<Scope> mcb = forResourceServer(resourceServer.getId())
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name);
|
||||
|
||||
if (tx.getCount(mcb) > 0) {
|
||||
if (tx.getCount(withCriteria(mcb)) > 0) {
|
||||
throw new ModelDuplicateException("Scope with name '" + name + "' for " + resourceServer.getId() + " already exists");
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,8 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
public Scope findById(String id, String resourceServerId) {
|
||||
LOG.tracef("findById(%s, %s)%s", id, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.read(forResourceServer(resourceServerId)
|
||||
.compare(Scope.SearchableFields.ID, Operator.EQ, id))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.orElse(null);
|
||||
|
@ -120,8 +120,8 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
public Scope findByName(String name, String resourceServerId) {
|
||||
LOG.tracef("findByName(%s, %s)%s", name, resourceServerId, getShortStackTrace());
|
||||
|
||||
return tx.read(forResourceServer(resourceServerId).compare(Scope.SearchableFields.NAME,
|
||||
Operator.EQ, name))
|
||||
return tx.read(withCriteria(forResourceServer(resourceServerId).compare(SearchableFields.NAME,
|
||||
Operator.EQ, name)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.orElse(null);
|
||||
|
@ -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.read(forResourceServer(id))
|
||||
return tx.read(withCriteria(forResourceServer(id)))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -155,7 +155,8 @@ public class MapScopeStore<K> implements ScopeStore {
|
|||
}
|
||||
}
|
||||
|
||||
return paginatedStream(tx.read(mcb).map(this::entityToAdapter), firstResult, maxResult)
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResult, SearchableFields.NAME))
|
||||
.map(this::entityToAdapter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@ import java.util.Objects;
|
|||
|
||||
public class MapPermissionTicketEntity<K> implements AbstractEntity<K> {
|
||||
|
||||
public static final Comparator<MapPermissionTicketEntity<?>> COMPARE_BY_RESOURCE_ID = Comparator.comparing(MapPermissionTicketEntity::getResourceId);
|
||||
|
||||
private final K id;
|
||||
private String owner;
|
||||
private String requester;
|
||||
|
|
|
@ -30,8 +30,6 @@ import java.util.Objects;
|
|||
|
||||
public class MapPolicyEntity<K> implements AbstractEntity<K> {
|
||||
|
||||
public static final Comparator<MapPolicyEntity<?>> COMPARE_BY_NAME = Comparator.comparing(MapPolicyEntity::getName);
|
||||
|
||||
private final K id;
|
||||
private String name;
|
||||
private String description;
|
||||
|
|
|
@ -29,8 +29,6 @@ import java.util.Set;
|
|||
|
||||
public class MapResourceEntity<K> implements AbstractEntity<K> {
|
||||
|
||||
public static final Comparator<MapResourceEntity<?>> COMPARE_BY_NAME = Comparator.comparing(MapResourceEntity::getName);
|
||||
|
||||
private final K id;
|
||||
private String name;
|
||||
private String displayName;
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import java.util.Comparator;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -45,9 +45,11 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
|||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import java.util.HashSet;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
|
||||
public class MapClientProvider<K> implements ClientProvider {
|
||||
|
||||
|
@ -57,8 +59,6 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
private final MapStorage<K, MapClientEntity<K>, ClientModel> clientStore;
|
||||
private final ConcurrentMap<K, ConcurrentMap<String, Integer>> clientRegisteredNodesStore;
|
||||
|
||||
private static final Comparator<MapClientEntity> COMPARE_BY_CLIENT_ID = Comparator.comparing(MapClientEntity::getClientId);
|
||||
|
||||
public MapClientProvider(KeycloakSession session, MapStorage<K, MapClientEntity<K>, ClientModel> clientStore, ConcurrentMap<K, ConcurrentMap<String, Integer>> clientRegisteredNodesStore) {
|
||||
this.session = session;
|
||||
this.clientStore = clientStore;
|
||||
|
@ -126,7 +126,11 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
|
||||
@Override
|
||||
public Stream<ClientModel> getClientsStream(RealmModel realm, Integer firstResult, Integer maxResults) {
|
||||
return paginatedStream(getClientsStream(realm), firstResult, maxResults);
|
||||
ModelCriteriaBuilder<ClientModel> mcb = clientStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.CLIENT_ID))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,10 +138,8 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
ModelCriteriaBuilder<ClientModel> mcb = clientStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
return tx.read(mcb)
|
||||
.sorted(COMPARE_BY_CLIENT_ID)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
;
|
||||
return tx.read(withCriteria(mcb).orderBy(SearchableFields.CLIENT_ID, ASCENDING))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -220,7 +222,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
ModelCriteriaBuilder<ClientModel> mcb = clientStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
return this.clientStore.getCount(mcb);
|
||||
return this.clientStore.getCount(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -248,7 +250,7 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.CLIENT_ID, Operator.ILIKE, clientId);
|
||||
|
||||
return tx.read(mcb)
|
||||
return tx.read(withCriteria(mcb))
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.findFirst()
|
||||
.orElse(null)
|
||||
|
@ -265,10 +267,8 @@ 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.read(mcb)
|
||||
.sorted(COMPARE_BY_CLIENT_ID);
|
||||
|
||||
return paginatedStream(s, firstResult, maxResults).map(entityToAdapterFunc(realm));
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.CLIENT_ID))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -280,10 +280,8 @@ public class MapClientProvider<K> implements ClientProvider {
|
|||
mcb = mcb.compare(SearchableFields.ATTRIBUTE, Operator.EQ, entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
Stream<MapClientEntity<K>> s = tx.read(mcb)
|
||||
.sorted(COMPARE_BY_CLIENT_ID);
|
||||
|
||||
return paginatedStream(s, firstResult, maxResults).map(entityToAdapterFunc(realm));
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.CLIENT_ID))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -344,7 +342,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.read(mcb)) {
|
||||
try (Stream<MapClientEntity<K>> st = tx.read(withCriteria(mcb))) {
|
||||
return st
|
||||
.filter(mce -> mce.getRedirectUris() != null && ! mce.getRedirectUris().isEmpty())
|
||||
.collect(Collectors.toMap(
|
||||
|
@ -358,7 +356,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.read(mcb)) {
|
||||
try (Stream<MapClientEntity<K>> toRemove = tx.read(withCriteria(mcb))) {
|
||||
toRemove
|
||||
.map(clientEntity -> session.clients().getClientById(realm, clientEntity.getId().toString()))
|
||||
.filter(Objects::nonNull)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package org.keycloak.models.map.clientscope;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -38,6 +37,8 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
|||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class MapClientScopeProvider<K> implements ClientScopeProvider {
|
||||
|
||||
|
@ -46,8 +47,6 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
|
|||
private final MapKeycloakTransaction<K, MapClientScopeEntity<K>, ClientScopeModel> tx;
|
||||
private final MapStorage<K, MapClientScopeEntity<K>, ClientScopeModel> clientScopeStore;
|
||||
|
||||
private static final Comparator<MapClientScopeEntity> COMPARE_BY_NAME = Comparator.comparing(MapClientScopeEntity::getName);
|
||||
|
||||
public MapClientScopeProvider(KeycloakSession session, MapStorage<K, MapClientScopeEntity<K>, ClientScopeModel> clientScopeStore) {
|
||||
this.session = session;
|
||||
this.clientScopeStore = clientScopeStore;
|
||||
|
@ -79,8 +78,7 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
|
|||
ModelCriteriaBuilder<ClientScopeModel> mcb = clientScopeStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
return tx.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME)
|
||||
return tx.read(withCriteria(mcb).orderBy(SearchableFields.NAME, ASCENDING))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
|
@ -91,7 +89,7 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name);
|
||||
|
||||
if (tx.getCount(mcb) > 0) {
|
||||
if (tx.getCount(withCriteria(mcb)) > 0) {
|
||||
throw new ModelDuplicateException("Client scope with name '" + name + "' in realm " + realm.getName());
|
||||
}
|
||||
|
||||
|
|
|
@ -30,15 +30,18 @@ import org.keycloak.models.map.storage.MapStorage;
|
|||
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import java.util.Comparator;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class MapGroupProvider<K> implements GroupProvider {
|
||||
|
||||
|
@ -88,10 +91,10 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
|
||||
@Override
|
||||
public Stream<GroupModel> getGroupsStream(RealmModel realm) {
|
||||
return getGroupsStreamInternal(realm, null);
|
||||
return getGroupsStreamInternal(realm, null, null);
|
||||
}
|
||||
|
||||
private Stream<GroupModel> getGroupsStreamInternal(RealmModel realm, UnaryOperator<ModelCriteriaBuilder<GroupModel>> modifier) {
|
||||
private Stream<GroupModel> getGroupsStreamInternal(RealmModel realm, UnaryOperator<ModelCriteriaBuilder<GroupModel>> modifier, UnaryOperator<QueryParameters<GroupModel>> queryParametersModifier) {
|
||||
LOG.tracef("getGroupsStream(%s)%s", realm, getShortStackTrace());
|
||||
ModelCriteriaBuilder<GroupModel> mcb = groupStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
@ -100,9 +103,13 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
mcb = modifier.apply(mcb);
|
||||
}
|
||||
|
||||
return tx.read(mcb)
|
||||
QueryParameters<GroupModel> queryParameters = withCriteria(mcb).orderBy(SearchableFields.NAME, ASCENDING);
|
||||
if (queryParametersModifier != null) {
|
||||
queryParameters = queryParametersModifier.apply(queryParameters);
|
||||
}
|
||||
|
||||
return tx.read(queryParameters)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.sorted(GroupModel.COMPARE_BY_NAME)
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -116,11 +123,8 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
mcb = mcb.compare(SearchableFields.NAME, Operator.ILIKE, "%" + search + "%");
|
||||
}
|
||||
|
||||
Stream<GroupModel> groupModelStream = tx.read(mcb)
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.sorted(Comparator.comparing(GroupModel::getName));
|
||||
|
||||
return paginatedStream(groupModelStream, first, max);
|
||||
return tx.read(withCriteria(mcb).pagination(first, max, SearchableFields.NAME))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -133,7 +137,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
mcb = mcb.compare(SearchableFields.PARENT_ID, Operator.EQ, (Object) null);
|
||||
}
|
||||
|
||||
return tx.getCount(mcb);
|
||||
return tx.getCount(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -142,45 +146,50 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.NAME, Operator.ILIKE, "%" + search + "%");
|
||||
|
||||
return tx.getCount(mcb);
|
||||
return tx.getCount(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getGroupsByRoleStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) {
|
||||
LOG.tracef("getGroupsByRole(%s, %s, %d, %d)%s", realm, role, firstResult, maxResults, getShortStackTrace());
|
||||
Stream<GroupModel> groupModelStream = getGroupsStreamInternal(realm,
|
||||
(ModelCriteriaBuilder<GroupModel> mcb) -> mcb.compare(SearchableFields.ASSIGNED_ROLE, Operator.EQ, role.getId())
|
||||
return getGroupsStreamInternal(realm,
|
||||
(ModelCriteriaBuilder<GroupModel> mcb) -> mcb.compare(SearchableFields.ASSIGNED_ROLE, Operator.EQ, role.getId()),
|
||||
qp -> qp.offset(firstResult).limit(maxResults)
|
||||
);
|
||||
|
||||
return paginatedStream(groupModelStream, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm) {
|
||||
LOG.tracef("getTopLevelGroupsStream(%s)%s", realm, getShortStackTrace());
|
||||
return getGroupsStreamInternal(realm,
|
||||
(ModelCriteriaBuilder<GroupModel> mcb) -> mcb.compare(SearchableFields.PARENT_ID, Operator.EQ, (Object) null)
|
||||
(ModelCriteriaBuilder<GroupModel> mcb) -> mcb.compare(SearchableFields.PARENT_ID, Operator.NOT_EXISTS),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm, Integer firstResult, Integer maxResults) {
|
||||
Stream<GroupModel> groupModelStream = getTopLevelGroupsStream(realm);
|
||||
|
||||
return paginatedStream(groupModelStream, firstResult, maxResults);
|
||||
|
||||
LOG.tracef("getTopLevelGroupsStream(%s, %s, %s)%s", realm, firstResult, maxResults, getShortStackTrace());
|
||||
return getGroupsStreamInternal(realm,
|
||||
(ModelCriteriaBuilder<GroupModel> mcb) -> mcb.compare(SearchableFields.PARENT_ID, Operator.NOT_EXISTS),
|
||||
qp -> qp.offset(firstResult).limit(maxResults)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> searchForGroupByNameStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
|
||||
LOG.tracef("searchForGroupByNameStream(%s, %s, %d, %d)%s", realm, search, firstResult, maxResults, getShortStackTrace());
|
||||
Stream<GroupModel> groupModelStream = getGroupsStreamInternal(realm,
|
||||
(ModelCriteriaBuilder<GroupModel> mcb) -> mcb.compare(SearchableFields.NAME, Operator.ILIKE, "%" + search + "%")
|
||||
);
|
||||
|
||||
final Stream<String> groups = paginatedStream(groupModelStream.map(GroupModel::getId), firstResult, maxResults);
|
||||
|
||||
return groups.map(id -> {
|
||||
ModelCriteriaBuilder<GroupModel> mcb = groupStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.NAME, Operator.ILIKE, "%" + search + "%");
|
||||
|
||||
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.NAME))
|
||||
.map(MapGroupEntity::getId)
|
||||
.map(groupStore.getKeyConvertor()::keyToString)
|
||||
.map(id -> {
|
||||
GroupModel groupById = session.groups().getGroupById(realm, id);
|
||||
while (Objects.nonNull(groupById.getParentId())) {
|
||||
groupById = session.groups().getGroupById(realm, groupById.getParentId());
|
||||
|
@ -201,7 +210,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
.compare(SearchableFields.PARENT_ID, Operator.EQ, parentId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name);
|
||||
|
||||
if (tx.getCount(mcb) > 0) {
|
||||
if (tx.getCount(withCriteria(mcb)) > 0) {
|
||||
throw new ModelDuplicateException("Group with name '" + name + "' in realm " + realm.getName() + " already exists for requested parent" );
|
||||
}
|
||||
|
||||
|
@ -243,7 +252,7 @@ public class MapGroupProvider<K> implements GroupProvider {
|
|||
session.users().preRemove(realm, group);
|
||||
realm.removeDefaultGroup(group);
|
||||
|
||||
group.getSubGroupsStream().forEach(subGroup -> session.groups().removeGroup(realm, subGroup));
|
||||
group.getSubGroupsStream().collect(Collectors.toSet()).forEach(subGroup -> session.groups().removeGroup(realm, subGroup));
|
||||
|
||||
// TODO: ^^^^^^^ Up to here
|
||||
|
||||
|
@ -268,7 +277,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.read(mcb)) {
|
||||
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.read(withCriteria(mcb))) {
|
||||
if (possibleSiblings.findAny().isPresent()) {
|
||||
throw new ModelDuplicateException("Parent already contains subgroup named '" + group.getName() + "'");
|
||||
}
|
||||
|
@ -290,7 +299,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.read(mcb)) {
|
||||
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.read(withCriteria(mcb))) {
|
||||
if (possibleSiblings.findAny().isPresent()) {
|
||||
throw new ModelDuplicateException("There is already a top level group named '" + subGroup.getName() + "'");
|
||||
}
|
||||
|
@ -304,7 +313,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.read(mcb)) {
|
||||
try (Stream<MapGroupEntity<K>> toRemove = tx.read(withCriteria(mcb))) {
|
||||
toRemove
|
||||
.map(groupEntity -> session.groups().getGroupById(realm, groupEntity.getId().toString()))
|
||||
.forEach(groupModel -> groupModel.deleteRoleMapping(role));
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.function.Function;
|
|||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
||||
|
@ -66,7 +67,7 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
|
|||
|
||||
LOG.tracef("getUserLoginFailure(%s, %s)%s", realm, userId, getShortStackTrace());
|
||||
|
||||
return userLoginFailureTx.read(mcb)
|
||||
return userLoginFailureTx.read(withCriteria(mcb))
|
||||
.findFirst()
|
||||
.map(userLoginFailureEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -80,7 +81,7 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
|
|||
|
||||
LOG.tracef("addUserLoginFailure(%s, %s)%s", realm, userId, getShortStackTrace());
|
||||
|
||||
MapUserLoginFailureEntity<K> userLoginFailureEntity = userLoginFailureTx.read(mcb).findFirst().orElse(null);
|
||||
MapUserLoginFailureEntity<K> userLoginFailureEntity = userLoginFailureTx.read(withCriteria(mcb)).findFirst().orElse(null);
|
||||
|
||||
if (userLoginFailureEntity == null) {
|
||||
userLoginFailureEntity = new MapUserLoginFailureEntity<>(userLoginFailureStore.getKeyConvertor().yieldNewUniqueKey(), realm.getId(), userId);
|
||||
|
@ -99,7 +100,7 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
|
|||
|
||||
LOG.tracef("removeUserLoginFailure(%s, %s)%s", realm, userId, getShortStackTrace());
|
||||
|
||||
userLoginFailureTx.delete(userLoginFailureStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
userLoginFailureTx.delete(userLoginFailureStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,7 +110,7 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
|
|||
|
||||
LOG.tracef("removeAllUserLoginFailures(%s)%s", realm, getShortStackTrace());
|
||||
|
||||
userLoginFailureTx.delete(userLoginFailureStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
userLoginFailureTx.delete(userLoginFailureStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,6 +38,8 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
|||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class MapRealmProvider<K> implements RealmProvider {
|
||||
|
||||
|
@ -110,7 +112,7 @@ public class MapRealmProvider<K> implements RealmProvider {
|
|||
ModelCriteriaBuilder<RealmModel> mcb = realmStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name);
|
||||
|
||||
K realmId = tx.read(mcb)
|
||||
K realmId = tx.read(withCriteria(mcb))
|
||||
.findFirst()
|
||||
.map(MapRealmEntity<K>::getId)
|
||||
.orElse(null);
|
||||
|
@ -132,9 +134,8 @@ public class MapRealmProvider<K> implements RealmProvider {
|
|||
}
|
||||
|
||||
private Stream<RealmModel> getRealmsStream(ModelCriteriaBuilder<RealmModel> mcb) {
|
||||
return tx.read(mcb)
|
||||
.map(this::entityToAdapter)
|
||||
.sorted(RealmModel.COMPARE_BY_NAME);
|
||||
return tx.read(withCriteria(mcb).orderBy(SearchableFields.NAME, ASCENDING))
|
||||
.map(this::entityToAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -174,7 +175,7 @@ public class MapRealmProvider<K> implements RealmProvider {
|
|||
ModelCriteriaBuilder<RealmModel> mcb = realmStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.CLIENT_INITIAL_ACCESS, Operator.EXISTS);
|
||||
|
||||
tx.read(mcb)
|
||||
tx.read(withCriteria(mcb))
|
||||
.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(MapRealmEntity<K>::removeExpiredClientInitialAccesses);
|
||||
}
|
||||
|
|
|
@ -25,14 +25,15 @@ import org.keycloak.models.RealmModel;
|
|||
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import java.util.Comparator;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel.SearchableFields;
|
||||
|
@ -47,19 +48,6 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
final MapKeycloakTransaction<K, MapRoleEntity<K>, RoleModel> tx;
|
||||
private final MapStorage<K, MapRoleEntity<K>, RoleModel> roleStore;
|
||||
|
||||
private static final Comparator<MapRoleEntity<?>> COMPARE_BY_NAME = new Comparator<MapRoleEntity<?>>() {
|
||||
@Override
|
||||
public int compare(MapRoleEntity<?> o1, MapRoleEntity<?> o2) {
|
||||
String r1 = o1 == null ? null : o1.getName();
|
||||
String r2 = o2 == null ? null : o2.getName();
|
||||
return r1 == r2 ? 0
|
||||
: r1 == null ? -1
|
||||
: r2 == null ? 1
|
||||
: r1.compareTo(r2);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
public MapRoleProvider(KeycloakSession session, MapStorage<K, MapRoleEntity<K>, RoleModel> roleStore) {
|
||||
this.session = session;
|
||||
this.roleStore = roleStore;
|
||||
|
@ -99,7 +87,12 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
|
||||
@Override
|
||||
public Stream<RoleModel> getRealmRolesStream(RealmModel realm, Integer first, Integer max) {
|
||||
return paginatedStream(getRealmRolesStream(realm), first, max);
|
||||
ModelCriteriaBuilder<RoleModel> mcb = roleStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.IS_CLIENT_ROLE, Operator.NE, true);
|
||||
|
||||
return tx.read(withCriteria(mcb).pagination(first, max, SearchableFields.NAME))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,8 +101,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.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME)
|
||||
return tx.read(withCriteria(mcb).orderBy(SearchableFields.NAME, ASCENDING))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
|
@ -136,7 +128,12 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
|
||||
@Override
|
||||
public Stream<RoleModel> getClientRolesStream(ClientModel client, Integer first, Integer max) {
|
||||
return paginatedStream(getClientRolesStream(client), first, max);
|
||||
ModelCriteriaBuilder<RoleModel> mcb = roleStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, client.getRealm().getId())
|
||||
.compare(SearchableFields.CLIENT_ID, Operator.EQ, client.getId());
|
||||
|
||||
return tx.read(withCriteria(mcb).pagination(first, max, SearchableFields.NAME))
|
||||
.map(entityToAdapterFunc(client.getRealm()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,8 +142,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.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME)
|
||||
return tx.read(withCriteria(mcb).orderBy(SearchableFields.NAME, ASCENDING))
|
||||
.map(entityToAdapterFunc(client.getRealm()));
|
||||
}
|
||||
@Override
|
||||
|
@ -197,7 +193,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.NAME, Operator.ILIKE, name);
|
||||
|
||||
String roleId = tx.read(mcb)
|
||||
String roleId = tx.read(withCriteria(mcb))
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.map(RoleModel::getId)
|
||||
.findFirst()
|
||||
|
@ -218,7 +214,7 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
.compare(SearchableFields.CLIENT_ID, Operator.EQ, client.getId())
|
||||
.compare(SearchableFields.NAME, Operator.ILIKE, name);
|
||||
|
||||
String roleId = tx.read(mcb)
|
||||
String roleId = tx.read(withCriteria(mcb))
|
||||
.map(entityToAdapterFunc(client.getRealm()))
|
||||
.map(RoleModel::getId)
|
||||
.findFirst()
|
||||
|
@ -254,10 +250,8 @@ public class MapRoleProvider<K> implements RoleProvider {
|
|||
roleStore.createCriteriaBuilder().compare(SearchableFields.DESCRIPTION, Operator.ILIKE, "%" + search + "%")
|
||||
);
|
||||
|
||||
Stream<MapRoleEntity<K>> s = tx.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME);
|
||||
|
||||
return paginatedStream(s.map(entityToAdapterFunc(realm)), first, max);
|
||||
return tx.read(withCriteria(mcb).pagination(first, max, SearchableFields.NAME))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -272,10 +266,8 @@ 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.read(mcb)
|
||||
.sorted(COMPARE_BY_NAME);
|
||||
|
||||
return paginatedStream(s,first, max).map(entityToAdapterFunc(client.getRealm()));
|
||||
return tx.read(withCriteria(mcb).pagination(first, max, SearchableFields.NAME))
|
||||
.map(entityToAdapterFunc(client.getRealm()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -58,20 +58,19 @@ public interface MapKeycloakTransaction<K, V extends AbstractEntity<K>, M> exten
|
|||
* transaction by methods {@link MapKeycloakTransaction#create}, {@link MapKeycloakTransaction#update},
|
||||
* {@link MapKeycloakTransaction#delete}, etc.
|
||||
*
|
||||
* @param mcb criteria to filter values
|
||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||
* @return values that fulfill the given criteria, that are updated based on changes in the current transaction
|
||||
*/
|
||||
Stream<V> read(ModelCriteriaBuilder<M> mcb);
|
||||
|
||||
Stream<V> read(QueryParameters<M> queryParameters);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||
* @return number of values present in the storage that fulfill the given criteria
|
||||
*/
|
||||
long getCount(ModelCriteriaBuilder<M> mcb);
|
||||
long getCount(QueryParameters<M> queryParameters);
|
||||
|
||||
/**
|
||||
* Instructs this transaction to force-update the {@code value} associated with the identifier {@code value.getId()} in the
|
||||
|
@ -116,8 +115,9 @@ public interface MapKeycloakTransaction<K, V extends AbstractEntity<K>, M> exten
|
|||
*
|
||||
* @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
|
||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||
* @return number of removed objects (might return {@code -1} if not supported)
|
||||
*/
|
||||
long delete(K artificialKey, ModelCriteriaBuilder<M> mcb);
|
||||
long delete(K artificialKey, QueryParameters<M> queryParameters);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,12 +20,14 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
/**
|
||||
* Implementation of this interface interacts with a persistence storage storing various entities, e.g. users, realms.
|
||||
* It contains basic object CRUD operations as well as bulk {@link #read(org.keycloak.models.map.storage.ModelCriteriaBuilder)}
|
||||
* and bulk {@link #delete(org.keycloak.models.map.storage.ModelCriteriaBuilder)} operations,
|
||||
* It contains basic object CRUD operations as well as bulk {@link #read(org.keycloak.models.map.storage.QueryParameters)}
|
||||
* and bulk {@link #delete(org.keycloak.models.map.storage.QueryParameters)} operations,
|
||||
* and operation for determining the number of the objects satisfying given criteria
|
||||
* ({@link #getCount(org.keycloak.models.map.storage.ModelCriteriaBuilder)}).
|
||||
* ({@link #getCount(org.keycloak.models.map.storage.QueryParameters)}).
|
||||
*
|
||||
* @author hmlnarik
|
||||
* @param <K> Type of the primary key. Various storages can
|
||||
|
@ -62,29 +64,27 @@ public interface MapStorage<K, V extends AbstractEntity<K>, M> {
|
|||
* Returns stream of objects satisfying given {@code criteria} from the storage.
|
||||
* The criteria are specified in the given criteria builder based on model properties.
|
||||
*
|
||||
* @param criteria Criteria filtering out the object, originally obtained
|
||||
* from {@link #createCriteriaBuilder()} method of this object.
|
||||
* If {@code null}, it returns an empty stream.
|
||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||
* @return Stream of objects. Never returns {@code null}.
|
||||
* @throws IllegalStateException If {@code criteria} is not compatible, i.e. has not been originally created
|
||||
* by the {@link #createCriteriaBuilder()} method of this object.
|
||||
*/
|
||||
Stream<V> read(ModelCriteriaBuilder<M> criteria);
|
||||
Stream<V> read(QueryParameters<M> queryParameters);
|
||||
|
||||
/**
|
||||
* Returns the number of objects satisfying given {@code criteria} from the storage.
|
||||
* The criteria are specified in the given criteria builder based on model properties.
|
||||
*
|
||||
* @param criteria
|
||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||
* @return Number of objects. Never returns {@code null}.
|
||||
* @throws IllegalStateException If {@code criteria} is not compatible, i.e. has not been originally created
|
||||
* by the {@link #createCriteriaBuilder()} method of this object.
|
||||
*/
|
||||
long getCount(ModelCriteriaBuilder<M> criteria);
|
||||
long getCount(QueryParameters<M> queryParameters);
|
||||
|
||||
/**
|
||||
* Updates the object with the key of the {@code value}'s ID in the storage if it already exists.
|
||||
* @param key Primary key of the object to update
|
||||
*
|
||||
* @param value Updated value
|
||||
* @throws NullPointerException if the object or its {@code id} is {@code null}
|
||||
* @see AbstractEntity#getId()
|
||||
|
@ -100,12 +100,12 @@ public interface MapStorage<K, V extends AbstractEntity<K>, M> {
|
|||
|
||||
/**
|
||||
* Deletes objects that match the given criteria.
|
||||
* @param criteria
|
||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||
* @return Number of removed objects (might return {@code -1} if not supported)
|
||||
* @throws IllegalStateException If {@code criteria} is not compatible, i.e. has not been originally created
|
||||
* by the {@link #createCriteriaBuilder()} method of this object.
|
||||
*/
|
||||
long delete(ModelCriteriaBuilder<M> criteria);
|
||||
long delete(QueryParameters<M> queryParameters);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -123,7 +123,6 @@ public interface MapStorage<K, V extends AbstractEntity<K>, M> {
|
|||
*/
|
||||
ModelCriteriaBuilder<M> createCriteriaBuilder();
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@code MapKeycloakTransaction} object that tracks a new transaction related to this storage.
|
||||
* In case of JPA or similar, the transaction object might be supplied by the container (via JTA) or
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
package org.keycloak.models.map.storage;
|
||||
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
|
||||
/**
|
||||
* Wraps together parameters for querying storage e.g. number of results to return, requested order or filtering criteria
|
||||
*
|
||||
* @param <M> Provide entity specific type checking, for example, when we create {@code QueryParameters}
|
||||
* instance for Users, M is equal to UserModel, hence we are not able, for example, to order result by a
|
||||
* {@link SearchableModelField} defined for clients in {@link org.keycloak.models.ClientModel}.
|
||||
*/
|
||||
public class QueryParameters<M> {
|
||||
|
||||
private Integer offset;
|
||||
private Integer limit;
|
||||
private final List<OrderBy<M>> orderBy = new LinkedList<>();
|
||||
private ModelCriteriaBuilder<M> mcb;
|
||||
|
||||
public QueryParameters() {
|
||||
}
|
||||
|
||||
public QueryParameters(ModelCriteriaBuilder<M> mcb) {
|
||||
this.mcb = mcb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code QueryParameters} instance initialized with {@link ModelCriteriaBuilder}
|
||||
*
|
||||
* @param mcb filtering criteria
|
||||
* @param <M> model type
|
||||
* @return a new {@code QueryParameters} instance
|
||||
*/
|
||||
public static <M> QueryParameters<M> withCriteria(ModelCriteriaBuilder<M> mcb) {
|
||||
return new QueryParameters<>(mcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets pagination (offset, limit and orderBy) parameters to {@code QueryParameters}
|
||||
*
|
||||
* @param offset
|
||||
* @param limit
|
||||
* @param orderByAscField
|
||||
* @return this object
|
||||
*/
|
||||
public QueryParameters<M> pagination(Integer offset, Integer limit, SearchableModelField<M> orderByAscField) {
|
||||
this.offset = offset;
|
||||
this.limit = limit;
|
||||
this.orderBy.add(new OrderBy<>(orderByAscField, ASCENDING));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets orderBy parameter; can be called repeatedly; fields are stored in a list where the first field has highest
|
||||
* priority when determining order; e.g. the second field is compared only when values for the first field are equal
|
||||
*
|
||||
* @param searchableModelField
|
||||
* @return this object
|
||||
*/
|
||||
public QueryParameters<M> orderBy(SearchableModelField<M> searchableModelField, Order order) {
|
||||
orderBy.add(new OrderBy<>(searchableModelField, order));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets offset parameter
|
||||
*
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public QueryParameters<M> offset(Integer offset) {
|
||||
this.offset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets limit parameter
|
||||
*
|
||||
* @param limit
|
||||
* @return
|
||||
*/
|
||||
public QueryParameters<M> limit(Integer limit) {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public Integer getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public ModelCriteriaBuilder<M> getModelCriteriaBuilder() {
|
||||
return mcb;
|
||||
}
|
||||
|
||||
public List<OrderBy<M>> getOrderBy() {
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum for ascending or descending ordering
|
||||
*/
|
||||
public enum Order {
|
||||
ASCENDING,
|
||||
DESCENDING
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for a field with its {@code Order}, ascending or descending
|
||||
*
|
||||
* @param <M>
|
||||
*/
|
||||
public static class OrderBy<M> {
|
||||
private final SearchableModelField<M> modelField;
|
||||
private final Order order;
|
||||
|
||||
public OrderBy(SearchableModelField<M> modelField, Order order) {
|
||||
this.modelField = modelField;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public SearchableModelField<M> getModelField() {
|
||||
return modelField;
|
||||
}
|
||||
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,8 @@ import org.jboss.logging.Logger;
|
|||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.utils.StreamsUtil;
|
||||
|
||||
public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>, M> implements MapKeycloakTransaction<K, V, M> {
|
||||
|
||||
|
@ -133,11 +135,11 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
|
|||
* 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
|
||||
* @param queryParameters
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Stream<V> read(ModelCriteriaBuilder<M> mcb) {
|
||||
public Stream<V> read(QueryParameters<M> queryParameters) {
|
||||
Predicate<? super V> filterOutAllBulkDeletedObjects = tasks.values().stream()
|
||||
.filter(BulkDeleteOperation.class::isInstance)
|
||||
.map(BulkDeleteOperation.class::cast)
|
||||
|
@ -145,7 +147,9 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
|
|||
.reduce(Predicate::and)
|
||||
.orElse(v -> true);
|
||||
|
||||
Stream<V> updatedAndNotRemovedObjectsStream = this.map.read(mcb)
|
||||
ModelCriteriaBuilder<M> mcb = queryParameters.getModelCriteriaBuilder();
|
||||
|
||||
Stream<V> updatedAndNotRemovedObjectsStream = this.map.read(queryParameters)
|
||||
.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);
|
||||
|
@ -159,12 +163,17 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
|
|||
updatedAndNotRemovedObjectsStream
|
||||
);
|
||||
|
||||
return res;
|
||||
if (!queryParameters.getOrderBy().isEmpty()) {
|
||||
res = res.sorted(MapFieldPredicates.getComparator(queryParameters.getOrderBy().stream()));
|
||||
}
|
||||
|
||||
|
||||
return StreamsUtil.paginatedStream(res, queryParameters.getOffset(), queryParameters.getLimit());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount(ModelCriteriaBuilder<M> mcb) {
|
||||
return read(mcb).count();
|
||||
public long getCount(QueryParameters<M> queryParameters) {
|
||||
return read(queryParameters).count();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,11 +219,11 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
|
|||
|
||||
|
||||
@Override
|
||||
public long delete(K artificialKey, ModelCriteriaBuilder<M> mcb) {
|
||||
public long delete(K artificialKey, QueryParameters<M> queryParameters) {
|
||||
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);
|
||||
final BulkDeleteOperation bdo = new BulkDeleteOperation(queryParameters);
|
||||
Predicate<V> filterForNonDeletedObjects = bdo.getFilterForNonDeletedObjects();
|
||||
long res = 0;
|
||||
for (Iterator<Entry<K, MapTaskWithValue>> it = tasks.entrySet().iterator(); it.hasNext();) {
|
||||
|
@ -355,29 +364,29 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
|
|||
|
||||
private class BulkDeleteOperation extends MapTaskWithValue {
|
||||
|
||||
private final ModelCriteriaBuilder<M> mcb;
|
||||
private final QueryParameters<M> queryParameters;
|
||||
|
||||
public BulkDeleteOperation(ModelCriteriaBuilder<M> mcb) {
|
||||
public BulkDeleteOperation(QueryParameters<M> queryParameters) {
|
||||
super(null);
|
||||
this.mcb = mcb;
|
||||
this.queryParameters = queryParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute() {
|
||||
map.delete(mcb);
|
||||
map.delete(queryParameters);
|
||||
}
|
||||
|
||||
public Predicate<V> getFilterForNonDeletedObjects() {
|
||||
if (! (mcb instanceof MapModelCriteriaBuilder)) {
|
||||
if (! (queryParameters.getModelCriteriaBuilder() instanceof MapModelCriteriaBuilder)) {
|
||||
return t -> true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final MapModelCriteriaBuilder<K, V, M> mmcb = (MapModelCriteriaBuilder<K, V, M>) mcb;
|
||||
final MapModelCriteriaBuilder<K, V, M> mmcb = (MapModelCriteriaBuilder<K, V, M>) queryParameters.getModelCriteriaBuilder();
|
||||
|
||||
Predicate<? super V> entityFilter = mmcb.getEntityFilter();
|
||||
Predicate<? super K> keyFilter = ((MapModelCriteriaBuilder) mcb).getKeyFilter();
|
||||
Predicate<? super K> keyFilter = mmcb.getKeyFilter();
|
||||
return v -> v == null || ! (keyFilter.test(v.getId()) && entityFilter.test(v));
|
||||
}
|
||||
|
||||
|
@ -387,7 +396,7 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
|
|||
}
|
||||
|
||||
private long getCount() {
|
||||
return map.getCount(mcb);
|
||||
return map.getCount(queryParameters);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,18 +21,23 @@ import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
|||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Stream;
|
||||
import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder.UpdatePredicatesFunc;
|
||||
import org.keycloak.models.map.storage.StringKeyConvertor;
|
||||
import java.util.Iterator;
|
||||
import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder.UpdatePredicatesFunc;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
|
@ -74,10 +79,11 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K>, M> impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public long delete(ModelCriteriaBuilder<M> criteria) {
|
||||
long res;
|
||||
public long delete(QueryParameters<M> queryParameters) {
|
||||
ModelCriteriaBuilder<M> criteria = queryParameters.getModelCriteriaBuilder();
|
||||
|
||||
if (criteria == null) {
|
||||
res = store.size();
|
||||
long res = store.size();
|
||||
store.clear();
|
||||
return res;
|
||||
}
|
||||
|
@ -88,15 +94,21 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K>, M> impleme
|
|||
}
|
||||
Predicate<? super K> keyFilter = b.getKeyFilter();
|
||||
Predicate<? super V> entityFilter = b.getEntityFilter();
|
||||
res = 0;
|
||||
for (Iterator<Entry<K, V>> iterator = store.entrySet().iterator(); iterator.hasNext();) {
|
||||
Entry<K, V> next = iterator.next();
|
||||
if (keyFilter.test(next.getKey()) && entityFilter.test(next.getValue())) {
|
||||
res++;
|
||||
iterator.remove();
|
||||
Stream<Entry<K, V>> storeStream = store.entrySet().stream();
|
||||
final AtomicLong res = new AtomicLong(0);
|
||||
|
||||
if (!queryParameters.getOrderBy().isEmpty()) {
|
||||
Comparator<V> comparator = MapFieldPredicates.getComparator(queryParameters.getOrderBy().stream());
|
||||
storeStream = storeStream.sorted((entry1, entry2) -> comparator.compare(entry1.getValue(), entry2.getValue()));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
paginatedStream(storeStream.filter(next -> keyFilter.test(next.getKey()) && entityFilter.test(next.getValue()))
|
||||
, queryParameters.getOffset(), queryParameters.getLimit())
|
||||
.peek(item -> {res.incrementAndGet();})
|
||||
.map(Entry::getKey)
|
||||
.forEach(store::remove);
|
||||
|
||||
return res.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,7 +129,9 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K>, M> impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public Stream<V> read(ModelCriteriaBuilder<M> criteria) {
|
||||
public Stream<V> read(QueryParameters<M> queryParameters) {
|
||||
ModelCriteriaBuilder<M> criteria = queryParameters.getModelCriteriaBuilder();
|
||||
|
||||
if (criteria == null) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
@ -135,8 +149,8 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K>, M> impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public long getCount(ModelCriteriaBuilder<M> criteria) {
|
||||
return read(criteria).count();
|
||||
public long getCount(QueryParameters<M> queryParameters) {
|
||||
return read(queryParameters).count();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
|
@ -171,7 +173,7 @@ public class ConcurrentHashMapStorageProviderFactory implements AmphibianProvide
|
|||
LOG.debugf("Storing contents to %s", f.getCanonicalPath());
|
||||
@SuppressWarnings("unchecked")
|
||||
final ModelCriteriaBuilder readAllCriteria = store.createCriteriaBuilder();
|
||||
Serialization.MAPPER.writeValue(f, store.read(readAllCriteria));
|
||||
Serialization.MAPPER.writeValue(f, store.read(withCriteria(readAllCriteria)));
|
||||
} else {
|
||||
LOG.debugf("Not storing contents of %s because directory not set", mapName);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,10 @@ import org.keycloak.models.map.group.MapGroupEntity;
|
|||
import org.keycloak.models.map.loginFailure.MapUserLoginFailureEntity;
|
||||
import org.keycloak.models.map.realm.MapRealmEntity;
|
||||
import org.keycloak.models.map.role.MapRoleEntity;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder.UpdatePredicatesFunc;
|
||||
|
@ -56,11 +59,11 @@ import org.keycloak.sessions.RootAuthenticationSessionModel;
|
|||
import org.keycloak.storage.StorageId;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.models.map.storage.CriterionNotSupportedException;
|
||||
import static org.keycloak.models.UserSessionModel.CORRESPONDING_SESSION_ID;
|
||||
|
@ -89,10 +92,11 @@ public class MapFieldPredicates {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final Map<Class<?>, Map> PREDICATES = new HashMap<>();
|
||||
private static final Map<SearchableModelField<?>, Comparator<?>> COMPARATORS = new HashMap<>();
|
||||
|
||||
static {
|
||||
put(REALM_PREDICATES, RealmModel.SearchableFields.NAME, MapRealmEntity::getName);
|
||||
put(REALM_PREDICATES, RealmModel.SearchableFields.CLIENT_INITIAL_ACCESS, MapRealmEntity::getClientInitialAccesses);
|
||||
putIncomparable(REALM_PREDICATES, RealmModel.SearchableFields.CLIENT_INITIAL_ACCESS, MapRealmEntity::getClientInitialAccesses);
|
||||
put(REALM_PREDICATES, RealmModel.SearchableFields.COMPONENT_PROVIDER_TYPE, MapFieldPredicates::checkRealmsWithComponentType);
|
||||
|
||||
put(CLIENT_PREDICATES, ClientModel.SearchableFields.REALM_ID, MapClientEntity::getRealmId);
|
||||
|
@ -136,7 +140,7 @@ public class MapFieldPredicates {
|
|||
put(AUTHENTICATION_SESSION_PREDICATES, RootAuthenticationSessionModel.SearchableFields.REALM_ID, MapRootAuthenticationSessionEntity::getRealmId);
|
||||
put(AUTHENTICATION_SESSION_PREDICATES, RootAuthenticationSessionModel.SearchableFields.TIMESTAMP, MapRootAuthenticationSessionEntity::getTimestamp);
|
||||
|
||||
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.ID, MapResourceServerEntity::getId);
|
||||
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.ID, predicateForKeyField(MapResourceServerEntity::getId));
|
||||
|
||||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.ID, predicateForKeyField(MapResourceEntity::getId));
|
||||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.NAME, MapResourceEntity::getName);
|
||||
|
@ -207,7 +211,14 @@ public class MapFieldPredicates {
|
|||
PREDICATES.put(UserLoginFailureModel.class, USER_LOGIN_FAILURE_PREDICATES);
|
||||
}
|
||||
|
||||
private static <K, V extends AbstractEntity<K>, M> void put(
|
||||
private static <K, V extends AbstractEntity<K>, M, L extends Comparable<L>> void put(
|
||||
Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> map,
|
||||
SearchableModelField<M> field, Function<V, L> extractor) {
|
||||
COMPARATORS.put(field, Comparator.comparing(extractor));
|
||||
map.put(field, (mcb, op, values) -> mcb.fieldCompare(op, extractor, values));
|
||||
}
|
||||
|
||||
private static <K, V extends AbstractEntity<K>, M> void putIncomparable(
|
||||
Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> map,
|
||||
SearchableModelField<M> field, Function<V, Object> extractor) {
|
||||
map.put(field, (mcb, op, values) -> mcb.fieldCompare(op, extractor, values));
|
||||
|
@ -219,7 +230,7 @@ public class MapFieldPredicates {
|
|||
map.put(field, function);
|
||||
}
|
||||
|
||||
private static <V extends AbstractEntity<?>> Function<V, Object> predicateForKeyField(Function<V, Object> extractor) {
|
||||
private static <V extends AbstractEntity<?>> Function<V, String> predicateForKeyField(Function<V, Object> extractor) {
|
||||
return entity -> {
|
||||
Object o = extractor.apply(entity);
|
||||
return o == null ? null : o.toString();
|
||||
|
@ -483,10 +494,35 @@ public class MapFieldPredicates {
|
|||
|
||||
protected static <K, V extends AbstractEntity<K>, M> Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> basePredicates(SearchableModelField<M> idField) {
|
||||
Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates = new HashMap<>();
|
||||
fieldPredicates.put(idField, (o, op, values) -> o.idCompare(op, values));
|
||||
fieldPredicates.put(idField, MapModelCriteriaBuilder::idCompare);
|
||||
return fieldPredicates;
|
||||
}
|
||||
|
||||
public static <K, V extends AbstractEntity<K>, M> Comparator<V> getComparator(QueryParameters.OrderBy<M> orderBy) {
|
||||
SearchableModelField<M> searchableModelField = orderBy.getModelField();
|
||||
QueryParameters.Order order = orderBy.getOrder();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Comparator<V> comparator = (Comparator<V>) COMPARATORS.get(searchableModelField);
|
||||
|
||||
if (comparator == null) {
|
||||
throw new IllegalArgumentException("Comparator for field " + searchableModelField.getName() + " is not configured.");
|
||||
}
|
||||
|
||||
if (order == QueryParameters.Order.DESCENDING) {
|
||||
return comparator.reversed();
|
||||
}
|
||||
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K, V extends AbstractEntity<K>, M> Comparator<V> getComparator(Stream<QueryParameters.OrderBy<M>> ordering) {
|
||||
return (Comparator<V>) ordering.map(MapFieldPredicates::getComparator)
|
||||
.reduce(Comparator::thenComparing)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Cannot create comparator for " + ordering));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K, V extends AbstractEntity<K>, M> Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> getPredicates(Class<M> clazz) {
|
||||
return PREDICATES.get(clazz);
|
||||
|
|
|
@ -23,12 +23,15 @@ import org.keycloak.models.map.common.AbstractEntity;
|
|||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.models.map.storage.StringKeyConvertor;
|
||||
import org.keycloak.models.map.userSession.MapAuthenticatedClientSessionEntity;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionEntity;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
/**
|
||||
* User session storage with a naive implementation of referential integrity in client to user session relation, restricted to
|
||||
* ON DELETE CASCADE functionality.
|
||||
|
@ -49,17 +52,19 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
|
|||
}
|
||||
|
||||
@Override
|
||||
public long delete(K artificialKey, ModelCriteriaBuilder<UserSessionModel> mcb) {
|
||||
Set<K> ids = read(mcb).map(AbstractEntity::getId).collect(Collectors.toSet());
|
||||
public long delete(K artificialKey, QueryParameters<UserSessionModel> queryParameters) {
|
||||
ModelCriteriaBuilder<UserSessionModel> mcb = queryParameters.getModelCriteriaBuilder();
|
||||
|
||||
Set<K> ids = read(queryParameters).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);
|
||||
clientSessionTr.delete(artificialKey, withCriteria(csMcb));
|
||||
return super.delete(artificialKey, queryParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(K key) {
|
||||
ModelCriteriaBuilder<AuthenticatedClientSessionModel> csMcb = clientSessionStore.createCriteriaBuilder().compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.EQ, key);
|
||||
clientSessionTr.delete(key, csMcb);
|
||||
clientSessionTr.delete(key, withCriteria(csMcb));
|
||||
super.delete(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,6 @@ public class MapUserEntity<K> implements AbstractEntity<K> {
|
|||
private String serviceAccountClientLink;
|
||||
private int notBefore;
|
||||
|
||||
static Comparator<MapUserEntity<?>> COMPARE_BY_USERNAME = Comparator.comparing(MapUserEntity::getUsername);
|
||||
|
||||
/**
|
||||
* Flag signalizing that any of the setters has been meaningfully used.
|
||||
*/
|
||||
|
|
|
@ -70,7 +70,8 @@ import static org.keycloak.models.UserModel.FIRST_NAME;
|
|||
import static org.keycloak.models.UserModel.LAST_NAME;
|
||||
import static org.keycloak.models.UserModel.USERNAME;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialStore.Streams {
|
||||
|
||||
|
@ -173,7 +174,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.read(mcb)
|
||||
tx.read(withCriteria(mcb))
|
||||
.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeFederatedIdentity(socialProvider));
|
||||
}
|
||||
|
@ -209,7 +210,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.read(mcb)
|
||||
return tx.read(withCriteria(mcb))
|
||||
.collect(Collectors.collectingAndThen(
|
||||
Collectors.toList(),
|
||||
list -> {
|
||||
|
@ -298,7 +299,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.read(mcb)
|
||||
return tx.read(withCriteria(mcb))
|
||||
.collect(Collectors.collectingAndThen(
|
||||
Collectors.toList(),
|
||||
list -> {
|
||||
|
@ -321,7 +322,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.USERNAME, Operator.EQ, username);
|
||||
|
||||
if (tx.getCount(mcb) > 0) {
|
||||
if (tx.getCount(withCriteria(mcb)) > 0) {
|
||||
throw new ModelDuplicateException("User with username '" + username + "' in realm " + realm.getName() + " already exists" );
|
||||
}
|
||||
|
||||
|
@ -362,7 +363,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
ModelCriteriaBuilder<UserModel> mcb = userStore.createCriteriaBuilder()
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
tx.delete(userStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
tx.delete(userStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -372,7 +373,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||
.compare(SearchableFields.FEDERATION_LINK, Operator.EQ, storageProviderId);
|
||||
|
||||
tx.delete(userStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
tx.delete(userStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -382,7 +383,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.setFederationLink(null));
|
||||
}
|
||||
|
@ -396,7 +397,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeRolesMembership(roleId));
|
||||
}
|
||||
|
@ -410,7 +411,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeGroupsMembership(groupId));
|
||||
}
|
||||
|
@ -424,7 +425,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(userEntity -> userEntity.removeUserConsent(clientId));
|
||||
}
|
||||
|
@ -444,7 +445,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
s.flatMap(MapUserEntity::getUserConsents)
|
||||
.forEach(consent -> consent.removeGrantedClientScopesIds(clientScopeId));
|
||||
}
|
||||
|
@ -462,7 +463,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
String providerIdS = new StorageId(componentId, "").getId();
|
||||
s.forEach(removeConsentsForExternalClient(providerIdS));
|
||||
}
|
||||
|
@ -490,7 +491,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
s.map(e -> registerEntityForChanges(tx, e))
|
||||
.forEach(entity -> entity.addRolesMembership(roleId));
|
||||
}
|
||||
|
@ -510,7 +511,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.read(mcb)) {
|
||||
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
|
||||
return s.findFirst()
|
||||
.map(entityToAdapterFunc(realm)).orElse(null);
|
||||
}
|
||||
|
@ -523,7 +524,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.read(mcb)
|
||||
List<MapUserEntity<K>> usersWithEmail = tx.read(withCriteria(mcb))
|
||||
.filter(userEntity -> Objects.equals(userEntity.getEmail(), email))
|
||||
.collect(Collectors.toList());
|
||||
if (usersWithEmail.isEmpty()) return null;
|
||||
|
@ -571,7 +572,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
mcb = mcb.compare(SearchableFields.SERVICE_ACCOUNT_CLIENT, Operator.NOT_EXISTS);
|
||||
}
|
||||
|
||||
return (int) tx.getCount(mcb);
|
||||
return (int) tx.getCount(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -584,8 +585,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
mcb = mcb.compare(SearchableFields.SERVICE_ACCOUNT_CLIENT, Operator.NOT_EXISTS);
|
||||
}
|
||||
|
||||
return paginatedStream(tx.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME), firstResult, maxResults)
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.USERNAME))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
|
@ -701,10 +701,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
|
|||
mcb = mcb.compare(SearchableFields.ASSIGNED_GROUP, Operator.IN, authorizedGroups);
|
||||
}
|
||||
|
||||
Stream<MapUserEntity<K>> usersStream = tx.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME); // Sort before paginating
|
||||
|
||||
return paginatedStream(usersStream, firstResult, maxResults) // paginate if necessary
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.USERNAME))
|
||||
.map(entityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -716,7 +713,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.read(mcb).sorted(MapUserEntity.COMPARE_BY_USERNAME), firstResult, maxResults)
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.USERNAME))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
|
@ -727,8 +724,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.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME)
|
||||
return tx.read(withCriteria(mcb).orderBy(SearchableFields.USERNAME, ASCENDING))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
|
@ -756,8 +752,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.read(mcb)
|
||||
.sorted(MapUserEntity.COMPARE_BY_USERNAME), firstResult, maxResults)
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.USERNAME))
|
||||
.map(entityToAdapterFunc(realm));
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -48,9 +47,9 @@ import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
|||
import static org.keycloak.models.UserSessionModel.CORRESPONDING_SESSION_ID;
|
||||
import static org.keycloak.models.UserSessionModel.SessionPersistenceState.TRANSIENT;
|
||||
import static org.keycloak.models.map.common.MapStorageUtils.registerEntityForChanges;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
import static org.keycloak.models.map.userSession.SessionExpiration.setClientSessionExpiration;
|
||||
import static org.keycloak.models.map.userSession.SessionExpiration.setUserSessionExpiration;
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
||||
|
@ -195,7 +194,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.read(mcb)
|
||||
return clientSessionTx.read(withCriteria(mcb))
|
||||
.findFirst()
|
||||
.map(clientEntityToAdapterFunc(client.getRealm(), client, userSession))
|
||||
.orElse(null);
|
||||
|
@ -258,7 +257,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
ModelCriteriaBuilder<UserSessionModel> mcb = realmAndOfflineCriteriaBuilder(realm, false)
|
||||
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uuid);
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.findFirst()
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -271,7 +270,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionsStream(%s, %s)%s", realm, user, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -283,7 +282,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionsStream(%s, %s)%s", realm, client, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -291,8 +290,16 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
@Override
|
||||
public Stream<UserSessionModel> getUserSessionsStream(RealmModel realm, ClientModel client,
|
||||
Integer firstResult, Integer maxResults) {
|
||||
return paginatedStream(getUserSessionsStream(realm, client)
|
||||
.sorted(Comparator.comparing(UserSessionModel::getLastSessionRefresh)), firstResult, maxResults);
|
||||
LOG.tracef("getUserSessionsStream(%s, %s, %s, %s)%s", realm, client, firstResult, maxResults, getShortStackTrace());
|
||||
|
||||
ModelCriteriaBuilder<UserSessionModel> mcb = realmAndOfflineCriteriaBuilder(realm, false)
|
||||
.compare(UserSessionModel.SearchableFields.CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, client.getId());
|
||||
|
||||
|
||||
return userSessionTx.read(withCriteria(mcb).pagination(firstResult, maxResults,
|
||||
UserSessionModel.SearchableFields.LAST_SESSION_REFRESH))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -302,7 +309,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionByBrokerUserIdStream(%s, %s)%s", realm, brokerUserId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -314,7 +321,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getUserSessionByBrokerSessionId(%s, %s)%s", realm, brokerSessionId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.findFirst()
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -347,7 +354,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getActiveUserSessions(%s, %s)%s", realm, client, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getCount(mcb);
|
||||
return userSessionTx.getCount(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -356,7 +363,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getActiveClientSessionStats(%s, %s)%s", realm, offline, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull)
|
||||
.map(UserSessionModel::getAuthenticatedClientSessions)
|
||||
|
@ -375,7 +382,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("removeUserSession(%s, %s)%s", realm, session, getShortStackTrace());
|
||||
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -386,7 +393,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("removeUserSessions(%s, %s)%s", realm, user, getShortStackTrace());
|
||||
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -405,7 +412,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("removeUserSessions(%s)%s", realm, getShortStackTrace());
|
||||
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -462,7 +469,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
UK uk = userSessionStore.getKeyConvertor().fromString(userSession.getNote(CORRESPONDING_SESSION_ID));
|
||||
mcb = realmAndOfflineCriteriaBuilder(realm, true)
|
||||
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uk);
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), mcb);
|
||||
userSessionTx.delete(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), withCriteria(mcb));
|
||||
userSession.removeNote(CORRESPONDING_SESSION_ID);
|
||||
}
|
||||
}
|
||||
|
@ -496,7 +503,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionsStream(%s, %s)%s", realm, user, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -508,7 +515,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionByBrokerSessionId(%s, %s)%s", realm, brokerSessionId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.findFirst()
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.orElse(null);
|
||||
|
@ -521,7 +528,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionByBrokerUserIdStream(%s, %s)%s", realm, brokerUserId, getShortStackTrace());
|
||||
|
||||
return userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -533,7 +540,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineSessionsCount(%s, %s)%s", realm, client, getShortStackTrace());
|
||||
|
||||
return userSessionTx.getCount(mcb);
|
||||
return userSessionTx.getCount(withCriteria(mcb));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -544,10 +551,10 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
|
|||
|
||||
LOG.tracef("getOfflineUserSessionsStream(%s, %s, %s, %s)%s", realm, client, firstResult, maxResults, getShortStackTrace());
|
||||
|
||||
return paginatedStream(userSessionTx.read(mcb)
|
||||
return userSessionTx.read(withCriteria(mcb).pagination(firstResult, maxResults,
|
||||
UserSessionModel.SearchableFields.LAST_SESSION_REFRESH))
|
||||
.map(userEntityToAdapterFunc(realm))
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(Comparator.comparing(UserSessionModel::getLastSessionRefresh)), firstResult, maxResults);
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -595,7 +602,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.read(mcb).findFirst().orElse(null);
|
||||
MapUserSessionEntity<UK> userSessionEntity = userSessionTx.read(withCriteria(mcb)).findFirst().orElse(null);
|
||||
if (userSessionEntity != null) {
|
||||
if (userSessionEntity.isOffline()) {
|
||||
return Stream.of(userSessionEntity);
|
||||
|
@ -604,7 +611,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.read(mcb);
|
||||
return userSessionTx.read(withCriteria(mcb));
|
||||
}
|
||||
|
||||
// it's online user session so lookup offline user session by corresponding session id reference
|
||||
|
@ -613,7 +620,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.read(mcb);
|
||||
return userSessionTx.read(withCriteria(mcb));
|
||||
}
|
||||
|
||||
return Stream.empty();
|
||||
|
|
|
@ -40,31 +40,6 @@ public class SearchableModelField<M> {
|
|||
return fieldClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 83 * hash + Objects.hashCode(this.name);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SearchableModelField<?> other = (SearchableModelField<?>) obj;
|
||||
if ( ! Objects.equals(this.name, other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SearchableModelField " + name + " @ " + getClass().getTypeParameters()[0].getTypeName();
|
||||
|
|
Loading…
Reference in a new issue