Skip to content

Commit

Permalink
p2-inc#287 Optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
rtufisi committed Jan 7, 2025
1 parent 2925c0b commit a5b0a8b
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 275 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public interface OrganizationModel extends WithAttributes {

Stream<OrganizationMemberModel> getOrganizationMembersStream();

Stream<OrganizationMemberModel> searchForOrganizationMembersStream(String search, Integer firstResult, Integer maxResults);
Stream<OrganizationMemberModel> searchForOrganizationMembersStream(
String search, Integer firstResult, Integer maxResults);

boolean hasMembership(UserModel user);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,19 @@
import io.phasetwo.service.util.IdentityProviders;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.From;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.From;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
Expand Down Expand Up @@ -210,35 +208,45 @@ public Stream<UserModel> searchForMembersStream(

@Override
public Stream<OrganizationMemberModel> getOrganizationMembersStream() {
TypedQuery<OrganizationMemberEntity> query = em.createNamedQuery("getOrganizationMembers", OrganizationMemberEntity.class);
TypedQuery<OrganizationMemberEntity> query =
em.createNamedQuery("getOrganizationMembers", OrganizationMemberEntity.class);
query.setParameter("organization", org);

return query.getResultStream()
.map(organizationMemberEntity -> new OrganizationMemberAdapter(session, realm, em, organizationMemberEntity));
return query
.getResultStream()
.map(
organizationMemberEntity ->
new OrganizationMemberAdapter(session, realm, em, organizationMemberEntity));
}

@Override
public Stream<OrganizationMemberModel> searchForOrganizationMembersStream(String search, Integer firstResult, Integer maxResults) {
public Stream<OrganizationMemberModel> searchForOrganizationMembersStream(
String search, Integer firstResult, Integer maxResults) {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<OrganizationMemberEntity> criteriaQuery = criteriaBuilder.createQuery(OrganizationMemberEntity.class);
CriteriaQuery<OrganizationMemberEntity> criteriaQuery =
criteriaBuilder.createQuery(OrganizationMemberEntity.class);

Root<OrganizationMemberEntity> root = criteriaQuery.from(OrganizationMemberEntity.class);

List<Predicate> predicates = new ArrayList<>();
// defining the organization search clause
predicates.add(criteriaBuilder.equal(root.get("organization"), org));
if (search != null && !search.isEmpty()) {
var userIds = userIdsSubquery(criteriaQuery, search);
var userIds = userIdsSubquery(criteriaQuery, search);
predicates.add(root.get("userId").in(userIds));
}

criteriaQuery.where(predicates.toArray(Predicate[]::new)).orderBy(criteriaBuilder.asc(root.get("createdAt")));
criteriaQuery
.where(predicates.toArray(Predicate[]::new))
.orderBy(criteriaBuilder.asc(root.get("createdAt")));

TypedQuery<OrganizationMemberEntity> query = em.createQuery(criteriaQuery);

return closing(paginateQuery(query, firstResult, maxResults).getResultStream())
.filter(Objects::nonNull)
.map(organizationMemberEntity -> new OrganizationMemberAdapter(session, realm, em, organizationMemberEntity));
.filter(Objects::nonNull)
.map(
organizationMemberEntity ->
new OrganizationMemberAdapter(session, realm, em, organizationMemberEntity));
}

private Subquery<String> userIdsSubquery(CriteriaQuery<?> query, String search) {
Expand All @@ -252,9 +260,9 @@ private Subquery<String> userIdsSubquery(CriteriaQuery<?> query, String search)
subqueryPredicates.add(cb.equal(subRoot.get("realmId"), realm.getId()));

List<Predicate> searchTermsPredicates = new ArrayList<>();
//define search terms
// define search terms
for (String stringToSearch : search.trim().split(",")) {
searchTermsPredicates.add(cb.or(getSearchOptionPredicateArray(stringToSearch, cb, subRoot)));
searchTermsPredicates.add(cb.or(getSearchOptionPredicateArray(stringToSearch, cb, subRoot)));
}
Predicate searchPredicate = cb.or(searchTermsPredicates.toArray(Predicate[]::new));
subqueryPredicates.add(searchPredicate);
Expand Down Expand Up @@ -379,7 +387,8 @@ public Stream<OrganizationRoleModel> getRolesByUserStream(UserModel user) {

@Override
public OrganizationMemberModel getMembershipDetails(UserModel user) {
TypedQuery<OrganizationMemberModel> query = em.createNamedQuery("getOrganizationMemberByUserId", OrganizationMemberModel.class);
TypedQuery<OrganizationMemberModel> query =
em.createNamedQuery("getOrganizationMemberByUserId", OrganizationMemberModel.class);
query.setParameter("organization", org);
query.setParameter("id", user.getId());
return query.getSingleResult();
Expand All @@ -403,7 +412,8 @@ public OrganizationRoleModel addRole(String name) {

@Override
public Stream<IdentityProviderModel> getIdentityProvidersStream() {
return session.identityProviders()
return session
.identityProviders()
.getAllStream()
// Todo: do we need to apply here a role filter? I believe not since its part of the
// HomeIdpDiscoverer
Expand All @@ -415,11 +425,12 @@ public Stream<IdentityProviderModel> getIdentityProvidersStream() {
});
}

private Predicate[] getSearchOptionPredicateArray(String value, CriteriaBuilder builder, From<?, UserEntity> from) {
private Predicate[] getSearchOptionPredicateArray(
String value, CriteriaBuilder builder, From<?, UserEntity> from) {
value = value.trim().toLowerCase();
List<Predicate> orPredicates = new ArrayList<>();
if (!value.isEmpty()) {
value = "%" + value + "%"; //contains in SQL query manner
value = "%" + value + "%"; // contains in SQL query manner
orPredicates.add(builder.like(from.get(USERNAME), value, ESCAPE_BACKSLASH));
orPredicates.add(builder.like(from.get(EMAIL), value, ESCAPE_BACKSLASH));
orPredicates.add(builder.like(builder.lower(from.get(FIRST_NAME)), value, ESCAPE_BACKSLASH));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,32 @@

import io.phasetwo.service.model.OrganizationMemberModel;
import io.phasetwo.service.model.OrganizationModel;
import io.phasetwo.service.model.OrganizationProvider;
import io.phasetwo.service.model.jpa.entity.OrganizationMemberEntity;
import io.phasetwo.service.model.jpa.entity.OrganizationMemberAttributeEntity;
import io.phasetwo.service.model.jpa.entity.OrganizationMemberEntity;
import io.phasetwo.service.model.jpa.entity.OrganizationRoleEntity;
import io.phasetwo.service.model.jpa.entity.UserOrganizationRoleMappingEntity;
import jakarta.persistence.EntityManager;
import java.util.List;
import java.util.Map;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.jpa.JpaModel;
import org.keycloak.models.utils.KeycloakModelUtils;

import java.util.List;
import java.util.Map;

public class OrganizationMemberAdapter implements OrganizationMemberModel, JpaModel<OrganizationMemberEntity> {
public class OrganizationMemberAdapter
implements OrganizationMemberModel, JpaModel<OrganizationMemberEntity> {

protected final KeycloakSession session;
protected final OrganizationMemberEntity organizationMemberEntity;
protected final EntityManager em;
protected final RealmModel realm;

public OrganizationMemberAdapter(
KeycloakSession session, RealmModel realm, EntityManager em, OrganizationMemberEntity organizationMemberEntity) {
KeycloakSession session,
RealmModel realm,
EntityManager em,
OrganizationMemberEntity organizationMemberEntity) {
this.session = session;
this.em = em;
this.organizationMemberEntity = organizationMemberEntity;
Expand All @@ -49,21 +51,21 @@ public String getUserId() {

@Override
public OrganizationModel getOrganization() {
return session
.getProvider(OrganizationProvider.class)
.getOrganizationById(realm, organizationMemberEntity.getOrganization().getId());
return new OrganizationAdapter(session, realm, em, organizationMemberEntity.getOrganization());
}

@Override
public List<String> getRoles() {
return organizationMemberEntity.getOrganization().getRoles()
.stream()
.flatMap(organizationRoleEntity -> organizationRoleEntity.getUserMappings().stream())
.filter(userOrganizationRoleMappingEntity ->
userOrganizationRoleMappingEntity.getUserId().equals(organizationMemberEntity.getUserId()))
.map(UserOrganizationRoleMappingEntity::getRole)
.map(OrganizationRoleEntity::getName)
.toList();
return organizationMemberEntity.getOrganization().getRoles().stream()
.flatMap(organizationRoleEntity -> organizationRoleEntity.getUserMappings().stream())
.filter(
userOrganizationRoleMappingEntity ->
userOrganizationRoleMappingEntity
.getUserId()
.equals(organizationMemberEntity.getUserId()))
.map(UserOrganizationRoleMappingEntity::getRole)
.map(OrganizationRoleEntity::getName)
.toList();
}

@Override
Expand All @@ -77,7 +79,9 @@ public Map<String, List<String>> getAttributes() {

@Override
public void removeAttribute(String name) {
organizationMemberEntity.getAttributes().removeIf(attribute -> attribute.getName().equals(name));
organizationMemberEntity
.getAttributes()
.removeIf(attribute -> attribute.getName().equals(name));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,75 +10,75 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import org.hibernate.annotations.Nationalized;

import java.util.Objects;
import org.hibernate.annotations.Nationalized;

@Table(
name = "ORGANIZATION_MEMBER_ATTRIBUTE",
uniqueConstraints = {@UniqueConstraint(columnNames = {"ORGANIZATION_MEMBER_ID", "NAME"})})
name = "ORGANIZATION_MEMBER_ATTRIBUTE",
uniqueConstraints = {@UniqueConstraint(columnNames = {"ORGANIZATION_MEMBER_ID", "NAME"})})
@Entity
public class OrganizationMemberAttributeEntity {

@Id
@Column(name = "ID", length = 36)
@Access(
AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This
// avoids an extra SQL
protected String id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ORGANIZATION_MEMBER_ID")
protected OrganizationMemberEntity organizationMember;

@Column(name = "NAME")
protected String name;

@Nationalized
@Column(name = "VALUE")
protected String value;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public OrganizationMemberEntity getOrganizationMember() {
return organizationMember;
}

public void setOrganizationMember(OrganizationMemberEntity organizationMember) {
this.organizationMember = organizationMember;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
OrganizationMemberAttributeEntity that = (OrganizationMemberAttributeEntity) o;
return Objects.equals(id, that.id) && Objects.equals(organizationMember, that.organizationMember);
}

@Override
public int hashCode() {
return Objects.hash(id, organizationMember);
}
@Id
@Column(name = "ID", length = 36)
@Access(
AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This
// avoids an extra SQL
protected String id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ORGANIZATION_MEMBER_ID")
protected OrganizationMemberEntity organizationMember;

@Column(name = "NAME")
protected String name;

@Nationalized
@Column(name = "VALUE")
protected String value;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public OrganizationMemberEntity getOrganizationMember() {
return organizationMember;
}

public void setOrganizationMember(OrganizationMemberEntity organizationMember) {
this.organizationMember = organizationMember;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
OrganizationMemberAttributeEntity that = (OrganizationMemberAttributeEntity) o;
return Objects.equals(id, that.id)
&& Objects.equals(organizationMember, that.organizationMember);
}

@Override
public int hashCode() {
return Objects.hash(id, organizationMember);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.persistence.UniqueConstraint;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
Expand Down
Loading

0 comments on commit a5b0a8b

Please sign in to comment.