This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch 3_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/3_0_X by this push:
new bc135bd76a [SYNCOPE-1871] Allow to search for Realms from multiple
bases (#1042)
bc135bd76a is described below
commit bc135bd76aa40e72223e0c4422de010c3091503c
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Tue Apr 1 17:42:50 2025 +0200
[SYNCOPE-1871] Allow to search for Realms from multiple bases (#1042)
---
.../clientapps/ClientAppModalPanelBuilder.java | 2 +-
.../client/console/status/ReconTaskPanel.java | 2 +-
.../wizards/resources/ConnectorDetailsPanel.java | 2 +-
.../client/console/SyncopeWebApplication.java | 2 +-
.../client/console/commons/RealmsUtils.java | 17 +++--
.../client/console/panels/RealmChoicePanel.java | 2 +-
.../console/tasks/SchedTaskWizardBuilder.java | 2 +-
.../client/console/wizards/any/Details.java | 2 +-
.../console/wizards/role/RoleWizardBuilder.java | 2 +-
.../syncope/common/rest/api/beans/RealmQuery.java | 39 +++++++---
.../org/apache/syncope/core/logic/RealmLogic.java | 22 ++++--
.../core/rest/cxf/service/RealmServiceImpl.java | 2 +-
.../syncope/core/persistence/api/dao/RealmDAO.java | 7 +-
.../core/persistence/jpa/dao/JPARealmDAO.java | 84 ++++++++++++----------
.../core/persistence/jpa/inner/RealmTest.java | 7 ++
.../persistence/jpa/dao/ElasticsearchRealmDAO.java | 41 ++++++++---
.../persistence/jpa/dao/OpenSearchRealmDAO.java | 43 +++++++----
.../syncope/fit/core/reference/TestCommand.java | 3 +-
.../org/apache/syncope/fit/core/RealmITCase.java | 12 ++++
19 files changed, 199 insertions(+), 94 deletions(-)
diff --git
a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java
b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java
index 09c2ab81ac..5276ae85b6 100644
---
a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java
+++
b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java
@@ -192,7 +192,7 @@ public class ClientAppModalPanelBuilder<T extends
ClientAppTO> extends AbstractM
@Override
protected Iterator<String> getChoices(final String input) {
return realmRestClient.search(fullRealmsTree
- ? RealmsUtils.buildRootQuery()
+ ? RealmsUtils.buildBaseQuery()
:
RealmsUtils.buildKeywordQuery(input)).getResult().stream().
map(RealmTO::getFullPath).collect(Collectors.toList()).iterator();
}
diff --git
a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
index 49be7e0733..f30c6022f0 100644
---
a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
+++
b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
@@ -140,7 +140,7 @@ public class ReconTaskPanel extends
MultilevelPanel.SecondLevel {
protected Iterator<String> getChoices(final String input) {
return (RealmsUtils.checkInput(input)
? (realmRestClient.search(fullRealmsTree
- ? RealmsUtils.buildRootQuery()
+ ? RealmsUtils.buildBaseQuery()
:
RealmsUtils.buildKeywordQuery(input)).getResult())
: List.<RealmTO>of()).stream().
map(RealmTO::getFullPath).collect(Collectors.toList()).iterator();
diff --git
a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
index 42f107c507..a4931c2161 100644
---
a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
+++
b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
@@ -68,7 +68,7 @@ public class ConnectorDetailsPanel extends WizardStep {
protected Iterator<String> getChoices(final String input) {
return (RealmsUtils.checkInput(input)
? (realmRestClient.search(fullRealmsTree
- ? RealmsUtils.buildRootQuery()
+ ? RealmsUtils.buildBaseQuery()
:
RealmsUtils.buildKeywordQuery(input)).getResult())
: List.<RealmTO>of()).stream().
map(RealmTO::getFullPath).collect(Collectors.toList()).iterator();
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
index 747bb0ff40..2a9f8011fa 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
@@ -327,7 +327,7 @@ public class SyncopeWebApplication extends
WicketBootSecuredWebApplication {
return false;
}
- RealmQuery query = RealmsUtils.buildRootQuery();
+ RealmQuery query = RealmsUtils.buildBaseQuery();
query.setPage(1);
query.setSize(0);
return restClient.search(query).getTotalCount() <
props.getRealmsFullTreeThreshold();
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/RealmsUtils.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/RealmsUtils.java
index e825642f29..e81664325a 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/RealmsUtils.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/RealmsUtils.java
@@ -18,6 +18,8 @@
*/
package org.apache.syncope.client.console.commons;
+import java.util.List;
+import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.common.lib.SyncopeConstants;
@@ -41,12 +43,15 @@ public final class RealmsUtils {
return new RealmQuery.Builder().keyword(input.contains("*") ? input :
"*" + input + "*").build();
}
- public static RealmQuery buildRootQuery() {
- String base =
SyncopeConsoleSession.get().getSearchableRealms().isEmpty()
- ||
SyncopeConsoleSession.get().getSearchableRealms().contains(SyncopeConstants.ROOT_REALM)
- ? SyncopeConstants.ROOT_REALM
- :
getFullPath(SyncopeConsoleSession.get().getSearchableRealms().get(0));
- return new RealmQuery.Builder().base(base).build();
+ public static RealmQuery buildBaseQuery() {
+ List<String> realms =
SyncopeConsoleSession.get().getSearchableRealms();
+
+ if (realms.isEmpty() || realms.contains(SyncopeConstants.ROOT_REALM)) {
+ return new
RealmQuery.Builder().base(SyncopeConstants.ROOT_REALM).build();
+ }
+
+ return new RealmQuery.Builder().bases(realms.stream().
+
map(RealmsUtils::getFullPath).collect(Collectors.toList())).build();
}
private RealmsUtils() {
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
index 412ec72df5..0485b1485e 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
@@ -453,7 +453,7 @@ public class RealmChoicePanel extends Panel {
protected Map<String, Pair<RealmTO, List<RealmTO>>> reloadRealmParentMap()
{
List<RealmTO> realmsToList = realmRestClient.search(fullRealmsTree
- ? RealmsUtils.buildRootQuery()
+ ? RealmsUtils.buildBaseQuery()
: RealmsUtils.buildKeywordQuery(searchQuery)).getResult();
return reloadRealmParentMap(realmsToList.stream().
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
index 0a10d24c59..4a01cabc12 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
@@ -119,7 +119,7 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO>
extends BaseAjaxWizar
protected List<String> searchRealms(final String realmQuery) {
return realmRestClient.search(fullRealmsTree
- ? RealmsUtils.buildRootQuery()
+ ? RealmsUtils.buildBaseQuery()
: RealmsUtils.buildKeywordQuery(realmQuery)).
getResult().stream().map(RealmTO::getFullPath).collect(Collectors.toList());
}
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
index e7e83a0cec..13dca07f9e 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
@@ -96,7 +96,7 @@ public class Details<T extends AnyTO> extends WizardStep {
return (pageRef.getPage() instanceof Realms
?
getRealmsFromLinks(Realms.class.cast(pageRef.getPage()).getRealmChoicePanel().getLinks())
: (fullRealmsTree
- ?
realmRestClient.search(RealmsUtils.buildRootQuery())
+ ?
realmRestClient.search(RealmsUtils.buildBaseQuery())
:
realmRestClient.search(RealmsUtils.buildKeywordQuery(input))).getResult()).
stream().filter(realm ->
authRealms.stream().anyMatch(
authRealm ->
realm.getFullPath().startsWith(authRealm))).
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java
index fc108a2a48..d37a130580 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java
@@ -196,7 +196,7 @@ public class RoleWizardBuilder extends
BaseAjaxWizardBuilder<RoleWrapper> {
@Override
protected Iterator<String> getChoices(final String input) {
return realmRestClient.search(fullRealmsTree
- ? RealmsUtils.buildRootQuery()
+ ? RealmsUtils.buildBaseQuery()
:
RealmsUtils.buildKeywordQuery(input)).getResult().stream().
map(RealmTO::getFullPath).collect(Collectors.toList()).iterator();
}
diff --git
a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/RealmQuery.java
b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/RealmQuery.java
index 9cd16b770e..fe65db7a4b 100644
---
a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/RealmQuery.java
+++
b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/RealmQuery.java
@@ -18,6 +18,12 @@
*/
package org.apache.syncope.common.rest.api.beans;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.ws.rs.QueryParam;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -38,15 +44,28 @@ public class RealmQuery extends AbstractQuery {
return this;
}
- public Builder base(final String base) {
- getInstance().setBase(base);
+ public Builder base(final String... bases) {
+ if (bases != null) {
+ Set<String> b =
Optional.ofNullable(getInstance().getBases()).orElseGet(HashSet::new);
+ b.addAll(Stream.of(bases).collect(Collectors.toSet()));
+ getInstance().setBases(b);
+ }
+ return this;
+ }
+
+ public Builder bases(final Collection<String> bases) {
+ if (bases != null) {
+ Set<String> b =
Optional.ofNullable(getInstance().getBases()).orElseGet(HashSet::new);
+ b.addAll(bases);
+ getInstance().setBases(b);
+ }
return this;
}
}
private String keyword;
- private String base;
+ private Set<String> bases;
public String getKeyword() {
return keyword;
@@ -57,13 +76,13 @@ public class RealmQuery extends AbstractQuery {
this.keyword = keyword;
}
- public String getBase() {
- return base;
+ public Set<String> getBases() {
+ return bases;
}
- @QueryParam("base")
- public void setBase(final String base) {
- this.base = base;
+ @QueryParam("bases")
+ public void setBases(final Set<String> bases) {
+ this.bases = bases;
}
@Override
@@ -81,7 +100,7 @@ public class RealmQuery extends AbstractQuery {
return new EqualsBuilder().
appendSuper(super.equals(obj)).
append(keyword, other.keyword).
- append(base, other.base).
+ append(bases, other.bases).
build();
}
@@ -90,7 +109,7 @@ public class RealmQuery extends AbstractQuery {
return new HashCodeBuilder().
appendSuper(super.hashCode()).
append(keyword).
- append(base).
+ append(bases).
build();
}
}
diff --git
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
index 70bf5f81a3..2d37f2d0f7 100644
---
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
+++
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.logic;
import java.lang.reflect.Method;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -29,6 +30,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.ProvisioningResult;
import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -59,6 +61,7 @@ import
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
import org.identityconnectors.framework.common.objects.Attribute;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
public class RealmLogic extends AbstractTransactionalLogic<RealmTO> {
@@ -114,16 +117,23 @@ public class RealmLogic extends
AbstractTransactionalLogic<RealmTO> {
@Transactional(readOnly = true)
public Pair<Integer, List<RealmTO>> search(
final String keyword,
- final String base,
+ final Set<String> bases,
final int page,
final int size) {
- Realm baseRealm = Optional.ofNullable(base == null ?
realmDAO.getRoot() : realmDAO.findByFullPath(base)).
- orElseThrow(() -> new NotFoundException(base));
+ Set<String> baseRealms = new HashSet<>();
+ if (CollectionUtils.isEmpty(bases)) {
+ baseRealms.add(SyncopeConstants.ROOT_REALM);
+ } else {
+ for (String base : bases) {
+
baseRealms.add(Optional.ofNullable(realmDAO.findByFullPath(base)).map(Realm::getFullPath).
+ orElseThrow(() -> new NotFoundException("Realm " +
base)));
+ }
+ }
- int count = realmDAO.countDescendants(baseRealm.getFullPath(),
keyword);
+ int count = realmDAO.countDescendants(baseRealms, keyword);
- List<Realm> result = realmDAO.findDescendants(baseRealm.getFullPath(),
keyword, page, size);
+ List<Realm> result = realmDAO.findDescendants(baseRealms, keyword,
page, size);
return Pair.of(
count,
@@ -154,7 +164,7 @@ public class RealmLogic extends
AbstractTransactionalLogic<RealmTO> {
}
}
-
securityChecks(AuthContextUtils.getAuthorizations().get(IdRepoEntitlement.REALM_CREATE),
parent.getFullPath());
+
securityChecks(AuthContextUtils.getAuthorizations().get(IdRepoEntitlement.REALM_CREATE),
parent.getFullPath());
String fullPath = StringUtils.appendIfMissing(parent.getFullPath(),
"/") + realmTO.getName();
if (realmDAO.findByFullPath(fullPath) != null) {
diff --git
a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RealmServiceImpl.java
b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RealmServiceImpl.java
index 8056149e3c..46e8b01316 100644
---
a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RealmServiceImpl.java
+++
b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RealmServiceImpl.java
@@ -47,7 +47,7 @@ public class RealmServiceImpl extends AbstractService
implements RealmService {
public PagedResult<RealmTO> search(final RealmQuery query) {
Pair<Integer, List<RealmTO>> result = logic.search(
Optional.ofNullable(query.getKeyword()).map(k ->
k.replace('*', '%')).orElse(null),
- query.getBase(),
+ query.getBases(),
query.getPage(),
query.getSize());
return buildPagedResult(result.getRight(), 1,
result.getRight().size(), result.getLeft());
diff --git
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RealmDAO.java
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RealmDAO.java
index a0a573caaa..fb26260149 100644
---
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RealmDAO.java
+++
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RealmDAO.java
@@ -19,6 +19,7 @@
package org.apache.syncope.core.persistence.api.dao;
import java.util.List;
+import java.util.Set;
import java.util.regex.Pattern;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.Implementation;
@@ -43,10 +44,14 @@ public interface RealmDAO extends DAO<Realm> {
int countDescendants(String base, String keyword);
+ int countDescendants(Set<String> bases, String keyword);
+
List<Realm> findDescendants(String base, String keyword, int page, int
itemsPerPage);
+ List<Realm> findDescendants(Set<String> bases, String keyword, int page,
int itemsPerPage);
+
List<String> findDescendants(String base, String prefix);
-
+
<T extends Policy> List<Realm> findByPolicy(T policy);
List<Realm> findByLogicActions(Implementation logicActions);
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
index aa1f867155..d4d94ba874 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.jpa.dao;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.NoResultException;
import javax.persistence.Query;
@@ -50,6 +51,34 @@ import
org.springframework.transaction.annotation.Transactional;
public class JPARealmDAO extends AbstractDAO<Realm> implements RealmDAO {
+ protected static int setParameter(final List<Object> parameters, final
Object parameter) {
+ parameters.add(parameter);
+ return parameters.size();
+ }
+
+ protected static StringBuilder buildDescendantsQuery(
+ final Set<String> bases,
+ final String keyword,
+ final List<Object> parameters) {
+
+ String basesClause = bases.stream().
+ map(base -> "e.fullPath=?" + setParameter(parameters, base)
+ + " OR e.fullPath LIKE ?" + setParameter(
+ parameters, SyncopeConstants.ROOT_REALM.equals(base) ?
"/%" : base + "/%")).
+ collect(Collectors.joining(" OR "));
+
+ StringBuilder queryString = new StringBuilder("SELECT e FROM ").
+ append(JPARealm.class.getSimpleName()).append(" e ").
+ append("WHERE (").append(basesClause).append(')');
+
+ if (keyword != null) {
+ queryString.append(" AND LOWER(e.name) LIKE ?").
+ append(setParameter(parameters, "%" +
keyword.replaceAll("_", "\\\\_").toLowerCase() + "%"));
+ }
+
+ return queryString;
+ }
+
protected final RoleDAO roleDAO;
protected final ApplicationEventPublisher publisher;
@@ -123,37 +152,16 @@ public class JPARealmDAO extends AbstractDAO<Realm>
implements RealmDAO {
return query.getResultList();
}
- protected int setParameter(final List<Object> parameters, final Object
parameter) {
- parameters.add(parameter);
- return parameters.size();
- }
-
- protected StringBuilder buildDescendantQuery(
- final String base,
- final String keyword,
- final List<Object> parameters) {
-
- StringBuilder queryString = new StringBuilder("SELECT e FROM ").
- append(JPARealm.class.getSimpleName()).append(" e ").
- append("WHERE (e.fullPath=?").
- append(setParameter(parameters, base)).
- append(" OR e.fullPath LIKE ?").
- append(setParameter(parameters,
SyncopeConstants.ROOT_REALM.equals(base) ? "/%" : base + "/%")).
- append(')');
-
- if (keyword != null) {
- queryString.append(" AND LOWER(e.name) LIKE ?").
- append(setParameter(parameters, "%" +
keyword.replaceAll("_", "\\\\_").toLowerCase() + "%"));
- }
-
- return queryString;
+ @Override
+ public int countDescendants(final String base, final String keyword) {
+ return countDescendants(Set.of(base), keyword);
}
@Override
- public int countDescendants(final String base, final String keyword) {
+ public int countDescendants(final Set<String> bases, final String keyword)
{
List<Object> parameters = new ArrayList<>();
- StringBuilder queryString = buildDescendantQuery(base, keyword,
parameters);
+ StringBuilder queryString = buildDescendantsQuery(bases, keyword,
parameters);
Query query = entityManager().createQuery(StringUtils.replaceOnce(
queryString.toString(),
"SELECT e ",
@@ -173,9 +181,19 @@ public class JPARealmDAO extends AbstractDAO<Realm>
implements RealmDAO {
final int page,
final int itemsPerPage) {
+ return findDescendants(Set.of(base), keyword, page, itemsPerPage);
+ }
+
+ @Override
+ public List<Realm> findDescendants(
+ final Set<String> bases,
+ final String keyword,
+ final int page,
+ final int itemsPerPage) {
+
List<Object> parameters = new ArrayList<>();
- StringBuilder queryString = buildDescendantQuery(base, keyword,
parameters);
+ StringBuilder queryString = buildDescendantsQuery(bases, keyword,
parameters);
TypedQuery<Realm> query = entityManager().createQuery(
queryString.append(" ORDER BY e.fullPath").toString(),
Realm.class);
@@ -196,7 +214,7 @@ public class JPARealmDAO extends AbstractDAO<Realm>
implements RealmDAO {
public List<String> findDescendants(final String base, final String
prefix) {
List<Object> parameters = new ArrayList<>();
- StringBuilder queryString = buildDescendantQuery(base, null,
parameters);
+ StringBuilder queryString = buildDescendantsQuery(Set.of(base), null,
parameters);
TypedQuery<Realm> query = entityManager().createQuery(queryString.
append(" AND (e.fullPath=?").
append(setParameter(parameters, prefix)).
@@ -298,16 +316,6 @@ public class JPARealmDAO extends AbstractDAO<Realm>
implements RealmDAO {
return query.getResultList();
}
- protected StringBuilder buildDescendantQuery(final String base, final
List<Object> parameters) {
- return new StringBuilder("SELECT e FROM ").
- append(JPARealm.class.getSimpleName()).append(" e ").
- append("WHERE e.fullPath=?").
- append(setParameter(parameters, base)).
- append(" OR e.fullPath LIKE ?").
- append(setParameter(parameters,
SyncopeConstants.ROOT_REALM.equals(base) ? "/%" : base + "/%")).
- append(" ORDER BY e.fullPath");
- }
-
protected String buildFullPath(final Realm realm) {
return realm.getParent() == null
? SyncopeConstants.ROOT_REALM
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RealmTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RealmTest.java
index 2115cf9250..3f48702336 100644
---
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RealmTest.java
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RealmTest.java
@@ -27,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.List;
+import java.util.Set;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.EntityViolationType;
import
org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
@@ -99,6 +100,12 @@ public class RealmTest extends AbstractTest {
assertNotNull(list);
assertFalse(list.isEmpty());
list.forEach(Assertions::assertNotNull);
+
+ list = realmDAO.findDescendants(Set.of("/even", "/odd"), null, -1, -1);
+ assertEquals(3, list.size());
+ assertNotNull(list.stream().filter(realm ->
"even".equals(realm.getName())).findFirst().orElseThrow());
+ assertNotNull(list.stream().filter(realm ->
"two".equals(realm.getName())).findFirst().orElseThrow());
+ assertNotNull(list.stream().filter(realm ->
"odd".equals(realm.getName())).findFirst().orElseThrow());
}
@Test
diff --git
a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchRealmDAO.java
b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchRealmDAO.java
index 326426181d..2dc61a0a22 100644
---
a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchRealmDAO.java
+++
b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchRealmDAO.java
@@ -29,7 +29,9 @@ import
co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch.core.CountRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.search.Hit;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeConstants;
@@ -131,13 +133,16 @@ public class ElasticsearchRealmDAO extends JPARealmDAO {
return result.stream().map(this::find).collect(Collectors.toList());
}
- protected Query buildDescendantQuery(final String base, final String
keyword) {
- Query prefix = new
Query.Builder().disMax(QueryBuilders.disMax().queries(
- new Query.Builder().term(QueryBuilders.term().
- field("fullPath").value(base).build()).build(),
- new Query.Builder().regexp(QueryBuilders.regexp().
-
field("fullPath").value(SyncopeConstants.ROOT_REALM.equals(base) ? "/.*" : base
+ "/.*").
- build()).build()).build()).build();
+ protected static Query buildDescendantsQuery(final Set<String> bases,
final String keyword) {
+ List<Query> basesQueries = new ArrayList<>();
+ bases.forEach(base -> {
+ basesQueries.add(new Query.Builder().term(QueryBuilders.term().
+ field("fullPath").value(base).build()).build());
+ basesQueries.add(new Query.Builder().regexp(QueryBuilders.regexp().
+
field("fullPath").value(SyncopeConstants.ROOT_REALM.equals(base) ? "/.*" : base
+ "/.*").
+ build()).build());
+ });
+ Query prefix = new
Query.Builder().disMax(QueryBuilders.disMax().queries(basesQueries).build()).build();
if (keyword == null) {
return prefix;
@@ -167,9 +172,14 @@ public class ElasticsearchRealmDAO extends JPARealmDAO {
@Override
public int countDescendants(final String base, final String keyword) {
+ return countDescendants(Set.of(base), keyword);
+ }
+
+ @Override
+ public int countDescendants(final Set<String> bases, final String keyword)
{
CountRequest request = new CountRequest.Builder().
index(ElasticsearchUtils.getRealmIndex(AuthContextUtils.getDomain())).
- query(buildDescendantQuery(base, keyword)).
+ query(buildDescendantsQuery(bases, keyword)).
build();
try {
@@ -187,10 +197,20 @@ public class ElasticsearchRealmDAO extends JPARealmDAO {
final int page,
final int itemsPerPage) {
+ return findDescendants(Set.of(base), keyword, page, itemsPerPage);
+ }
+
+ @Override
+ public List<Realm> findDescendants(
+ final Set<String> bases,
+ final String keyword,
+ final int page,
+ final int itemsPerPage) {
+
SearchRequest request = new SearchRequest.Builder().
index(ElasticsearchUtils.getRealmIndex(AuthContextUtils.getDomain())).
searchType(SearchType.QueryThenFetch).
- query(buildDescendantQuery(base, keyword)).
+ query(buildDescendantsQuery(bases, keyword)).
from(itemsPerPage * (page <= 0 ? 0 : page - 1)).
size(itemsPerPage < 0 ? indexMaxResultWindow : itemsPerPage).
sort(ES_SORT_OPTIONS_REALM).
@@ -218,8 +238,7 @@ public class ElasticsearchRealmDAO extends JPARealmDAO {
build()).build()).build()).build();
Query query = new Query.Builder().bool(QueryBuilders.bool().must(
- buildDescendantQuery(base, (String) null),
- prefixQuery).build()).
+ buildDescendantsQuery(Set.of(base), null),
prefixQuery).build()).
build();
SearchRequest request = new SearchRequest.Builder().
diff --git
a/ext/opensearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OpenSearchRealmDAO.java
b/ext/opensearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OpenSearchRealmDAO.java
index 082af104a2..23e0c88f43 100644
---
a/ext/opensearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OpenSearchRealmDAO.java
+++
b/ext/opensearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OpenSearchRealmDAO.java
@@ -18,7 +18,9 @@
*/
package org.apache.syncope.core.persistence.jpa.dao;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeConstants;
@@ -131,14 +133,16 @@ public class OpenSearchRealmDAO extends JPARealmDAO {
return result.stream().map(this::find).collect(Collectors.toList());
}
- protected Query buildDescendantQuery(final String base, final String
keyword) {
- Query prefix = new
Query.Builder().disMax(QueryBuilders.disMax().queries(
- new Query.Builder().term(QueryBuilders.term().
-
field("fullPath").value(FieldValue.of(base)).build()).build(),
- new Query.Builder().regexp(QueryBuilders.regexp().
-
field("fullPath").value(SyncopeConstants.ROOT_REALM.equals(base) ? "/.*" : base
+ "/.*").
- build()).build()).build()).build();
-
+ protected Query buildDescendantsQuery(final Set<String> bases, final
String keyword) {
+ List<Query> basesQueries = new ArrayList<>();
+ bases.forEach(base -> {
+ basesQueries.add(new Query.Builder().term(QueryBuilders.term().
+
field("fullPath").value(FieldValue.of(base)).build()).build());
+ basesQueries.add(new Query.Builder().regexp(QueryBuilders.regexp().
+
field("fullPath").value(SyncopeConstants.ROOT_REALM.equals(base) ? "/.*" : base
+ "/.*").
+ build()).build());
+ });
+ Query prefix = new
Query.Builder().disMax(QueryBuilders.disMax().queries(basesQueries).build()).build();
if (keyword == null) {
return prefix;
}
@@ -167,15 +171,20 @@ public class OpenSearchRealmDAO extends JPARealmDAO {
@Override
public int countDescendants(final String base, final String keyword) {
+ return countDescendants(Set.of(base), keyword);
+ }
+
+ @Override
+ public int countDescendants(final Set<String> bases, final String keyword)
{
CountRequest request = new CountRequest.Builder().
index(OpenSearchUtils.getRealmIndex(AuthContextUtils.getDomain())).
- query(buildDescendantQuery(base, keyword)).
+ query(buildDescendantsQuery(bases, keyword)).
build();
try {
return (int) client.count(request).count();
} catch (Exception e) {
- LOG.error("While counting in OpenSearch", e);
+ LOG.error("While counting in Elasticsearch", e);
return 0;
}
}
@@ -187,10 +196,20 @@ public class OpenSearchRealmDAO extends JPARealmDAO {
final int page,
final int itemsPerPage) {
+ return findDescendants(Set.of(base), keyword, page, itemsPerPage);
+ }
+
+ @Override
+ public List<Realm> findDescendants(
+ final Set<String> bases,
+ final String keyword,
+ final int page,
+ final int itemsPerPage) {
+
SearchRequest request = new SearchRequest.Builder().
index(OpenSearchUtils.getRealmIndex(AuthContextUtils.getDomain())).
searchType(SearchType.QueryThenFetch).
- query(buildDescendantQuery(base, keyword)).
+ query(buildDescendantsQuery(bases, keyword)).
from(itemsPerPage * (page <= 0 ? 0 : page - 1)).
size(itemsPerPage < 0 ? indexMaxResultWindow : itemsPerPage).
sort(ES_SORT_OPTIONS_REALM).
@@ -218,7 +237,7 @@ public class OpenSearchRealmDAO extends JPARealmDAO {
build()).build()).build()).build();
Query query = new Query.Builder().bool(QueryBuilders.bool().must(
- buildDescendantQuery(base, (String) null),
+ buildDescendantsQuery(Set.of(base), null),
prefixQuery).build()).
build();
diff --git
a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestCommand.java
b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestCommand.java
index 290b283e8b..6382d770c2 100644
---
a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestCommand.java
+++
b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestCommand.java
@@ -19,6 +19,7 @@
package org.apache.syncope.fit.core.reference;
import java.util.Optional;
+import java.util.Set;
import org.apache.syncope.common.lib.Attr;
import org.apache.syncope.common.lib.request.AnyObjectCR;
import org.apache.syncope.common.lib.to.AnyObjectTO;
@@ -43,7 +44,7 @@ public class TestCommand implements Command<TestCommandArgs> {
private AnyObjectLogic anyObjectLogic;
private Optional<RealmTO> getRealm(final String fullPath) {
- return realmLogic.search(null, fullPath, -1, -1).getRight().stream().
+ return realmLogic.search(null, Set.of(fullPath), -1,
-1).getRight().stream().
filter(realm ->
fullPath.equals(realm.getFullPath())).findFirst();
}
diff --git
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
index b7f5f73ff9..358a591e7c 100644
---
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
+++
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.fit.core;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -465,4 +466,15 @@ public class RealmITCase extends AbstractITCase {
ROLE_SERVICE.delete(role.getKey());
}
}
+
+ @Test
+ public void issueSYNCOPE1871() {
+ PagedResult<RealmTO> result = REALM_SERVICE.search(new
RealmQuery.Builder().base("/odd").base("/even").build());
+ assertDoesNotThrow(() -> result.getResult().stream().
+ filter(r ->
"odd".equals(r.getName())).findFirst().orElseThrow());
+ assertDoesNotThrow(() -> result.getResult().stream().
+ filter(r ->
"even".equals(r.getName())).findFirst().orElseThrow());
+ assertDoesNotThrow(() -> result.getResult().stream().
+ filter(r ->
"two".equals(r.getName())).findFirst().orElseThrow());
+ }
}