diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
index abf6ff4392..cb46e5d156 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
@@ -28,9 +28,6 @@
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.DerSchema;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.Schema;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -45,11 +42,6 @@ public interface AnyDAO> extends DAO {
A authFind(String key);
- List findByPlainAttrValue(PlainSchema schema, PlainAttrValue attrValue, boolean ignoreCaseMatch);
-
- Optional findByPlainAttrUniqueValue(
- PlainSchema schema, PlainAttrUniqueValue attrUniqueValue, boolean ignoreCaseMatch);
-
/**
* Find any objects by derived attribute value. This method could fail if one or more string literals contained
* into the derived attribute value provided derive from identifier (schema key) replacement. When you are going to
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
index ec2daaee47..942d01d974 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
@@ -60,7 +60,7 @@ public static SearchCond of(final AbstractSearchCond leaf) {
return cond;
}
- public static SearchCond getNotLeaf(final AbstractSearchCond leaf) {
+ public static SearchCond negate(final AbstractSearchCond leaf) {
SearchCond cond = of(leaf);
cond.type = Type.NOT_LEAF;
@@ -68,7 +68,7 @@ public static SearchCond getNotLeaf(final AbstractSearchCond leaf) {
return cond;
}
- public static SearchCond and(final SearchCond left, final SearchCond right) {
+ private static SearchCond and(final SearchCond left, final SearchCond right) {
SearchCond cond = new SearchCond();
cond.type = Type.AND;
@@ -89,10 +89,10 @@ public static SearchCond and(final List conditions) {
}
public static SearchCond and(final SearchCond... conditions) {
- return or(Arrays.asList(conditions));
+ return and(Arrays.asList(conditions));
}
- public static SearchCond or(final SearchCond left, final SearchCond right) {
+ private static SearchCond or(final SearchCond left, final SearchCond right) {
SearchCond cond = new SearchCond();
cond.type = Type.OR;
@@ -135,11 +135,12 @@ public String hasAnyTypeCond() {
switch (type) {
case LEAF:
case NOT_LEAF:
- if (leaf instanceof AnyTypeCond) {
- anyTypeName = ((AnyTypeCond) leaf).getAnyTypeKey();
+ if (leaf instanceof AnyTypeCond anyTypeCond) {
+ anyTypeName = anyTypeCond.getAnyTypeKey();
}
break;
+
case AND:
case OR:
if (left != null) {
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
index 59514b2db8..32644ca883 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
@@ -207,7 +207,7 @@ protected SearchCond visitPrimitive(final SearchCondition sc) {
if (notEquals.isPresent() && notEquals.get().getType() == AttrCond.Type.ISNULL) {
notEquals.get().setType(AttrCond.Type.ISNOTNULL);
} else {
- leaf = SearchCond.getNotLeaf(leaf);
+ leaf = SearchCond.negate(leaf);
}
}
break;
diff --git a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java
index eccd4a1abc..4e767d4620 100644
--- a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java
+++ b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java
@@ -78,7 +78,7 @@ public void nieq() {
AnyCond anyCond = new AnyCond(AttrCond.Type.IEQ);
anyCond.setSchema("username");
anyCond.setExpression("rossini");
- SearchCond leaf = SearchCond.getNotLeaf(anyCond);
+ SearchCond leaf = SearchCond.negate(anyCond);
assertEquals(leaf, SearchCondConverter.convert(VISITOR, fiql));
}
@@ -117,7 +117,7 @@ public void nilike() {
AttrCond attrCond = new AnyCond(AttrCond.Type.ILIKE);
attrCond.setSchema("username");
attrCond.setExpression("ros%");
- SearchCond leaf = SearchCond.getNotLeaf(attrCond);
+ SearchCond leaf = SearchCond.negate(attrCond);
assertEquals(leaf, SearchCondConverter.convert(VISITOR, fiql));
}
diff --git a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AnyFinder.java b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AnyFinder.java
new file mode 100644
index 0000000000..f9dbb602ef
--- /dev/null
+++ b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AnyFinder.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.common.dao;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Pattern;
+import org.apache.commons.jexl3.parser.Parser;
+import org.apache.commons.jexl3.parser.ParserConstants;
+import org.apache.commons.jexl3.parser.Token;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.search.AttrCond;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.transaction.annotation.Transactional;
+
+public class AnyFinder {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(AnyFinder.class);
+
+ protected static final Comparator LITERAL_COMPARATOR = (l1, l2) -> {
+ if (l1 == null && l2 == null) {
+ return 0;
+ } else if (l1 != null && l2 == null) {
+ return -1;
+ } else if (l1 == null) {
+ return 1;
+ } else if (l1.length() == l2.length()) {
+ return 0;
+ } else if (l1.length() > l2.length()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ };
+
+ /**
+ * Split an attribute value recurring on provided literals/tokens.
+ *
+ * @param attrValue value to be split
+ * @param literals literals/tokens
+ * @return split value
+ */
+ protected static List split(final String attrValue, final List literals) {
+ final List attrValues = new ArrayList<>();
+
+ if (literals.isEmpty()) {
+ attrValues.add(attrValue);
+ } else {
+ for (String token : attrValue.split(Pattern.quote(literals.get(0)))) {
+ if (!token.isEmpty()) {
+ attrValues.addAll(split(token, literals.subList(1, literals.size())));
+ }
+ }
+ }
+
+ return attrValues;
+ }
+
+ protected final PlainSchemaDAO plainSchemaDAO;
+
+ protected final AnySearchDAO anySearchDAO;
+
+ public AnyFinder(final PlainSchemaDAO plainSchemaDAO, final AnySearchDAO anySearchDAO) {
+ this.plainSchemaDAO = plainSchemaDAO;
+ this.anySearchDAO = anySearchDAO;
+ }
+
+ @Transactional(readOnly = true)
+ public > Optional findByPlainAttrUniqueValue(
+ final AnyTypeKind anyTypeKind,
+ final PlainSchema schema,
+ final PlainAttrUniqueValue attrUniqueValue) {
+
+ AttrCond cond = new AttrCond(AttrCond.Type.EQ);
+ cond.setSchema(schema.getKey());
+ cond.setExpression(attrUniqueValue.getStringValue());
+
+ List result = anySearchDAO.search(SearchCond.of(cond), anyTypeKind);
+ if (result.isEmpty()) {
+ return Optional.empty();
+ }
+ return Optional.of(result.get(0));
+ }
+
+ @Transactional(readOnly = true)
+ public > List findByDerAttrValue(
+ final AnyTypeKind anyTypeKind,
+ final DerSchema derSchema,
+ final String value,
+ final boolean ignoreCaseMatch) {
+
+ if (derSchema == null) {
+ LOG.error("No DerSchema");
+ return List.of();
+ }
+
+ Parser parser = new Parser(derSchema.getExpression());
+
+ // Schema keys
+ List identifiers = new ArrayList<>();
+
+ // Literals
+ List literals = new ArrayList<>();
+
+ // Get schema keys and literals
+ for (Token token = parser.getNextToken(); token != null && StringUtils.isNotBlank(token.toString());
+ token = parser.getNextToken()) {
+
+ if (token.kind == ParserConstants.STRING_LITERAL) {
+ literals.add(token.toString().substring(1, token.toString().length() - 1));
+ }
+
+ if (token.kind == ParserConstants.IDENTIFIER) {
+ identifiers.add(token.toString());
+ }
+ }
+
+ // Sort literals in order to process later literals included into others
+ literals.sort(LITERAL_COMPARATOR);
+
+ // Split value on provided literals
+ List attrValues = split(value, literals);
+
+ if (attrValues.size() != identifiers.size()) {
+ LOG.error("Ambiguous JEXL expression resolution: literals and values have different size");
+ return List.of();
+ }
+
+ List andConditions = new ArrayList<>();
+
+ // Contains used identifiers in order to avoid replications
+ Set used = new HashSet<>();
+
+ // Create several clauses: one for eanch identifiers
+ for (int i = 0; i < identifiers.size() && !used.contains(identifiers.get(i)); i++) {
+ // verify schema existence and get schema type
+ PlainSchema schema = plainSchemaDAO.findById(identifiers.get(i)).orElse(null);
+
+ if (schema == null) {
+ LOG.error("Invalid schema '{}', ignoring", identifiers.get(i));
+ } else {
+ used.add(identifiers.get(i));
+
+ AttrCond cond = new AttrCond(ignoreCaseMatch ? AttrCond.Type.IEQ : AttrCond.Type.EQ);
+ cond.setSchema(schema.getKey());
+ cond.setExpression(attrValues.get(i));
+ andConditions.add(SearchCond.of(cond));
+ }
+ }
+
+ LOG.debug("Generated search {} conditions: {}", anyTypeKind, andConditions);
+
+ return anySearchDAO.search(SearchCond.and(andConditions), anyTypeKind);
+ }
+}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MariaDBPersistenceContext.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MariaDBPersistenceContext.java
index 337d5700fd..e8c8b39086 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MariaDBPersistenceContext.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MariaDBPersistenceContext.java
@@ -31,8 +31,6 @@
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.jpa.dao.AnyFinder;
-import org.apache.syncope.core.persistence.jpa.dao.MariaDBAnyFinder;
import org.apache.syncope.core.persistence.jpa.dao.MariaDBJPAAnySearchDAO;
import org.apache.syncope.core.persistence.jpa.dao.repo.MariaDBPlainSchemaRepoExtImpl;
import org.apache.syncope.core.persistence.jpa.dao.repo.PlainSchemaRepoExt;
@@ -53,12 +51,6 @@ public EntityFactory entityFactory() {
return new MariaDBEntityFactory();
}
- @ConditionalOnMissingBean
- @Bean
- public AnyFinder anyFinder(final @Lazy PlainSchemaDAO plainSchemaDAO, final EntityManager entityManager) {
- return new MariaDBAnyFinder(plainSchemaDAO, entityManager);
- }
-
@ConditionalOnMissingBean
@Bean
public AnySearchDAO anySearchDAO(
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MySQLPersistenceContext.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MySQLPersistenceContext.java
index 44b35dbcce..2bde40db09 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MySQLPersistenceContext.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MySQLPersistenceContext.java
@@ -31,8 +31,6 @@
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.jpa.dao.AnyFinder;
-import org.apache.syncope.core.persistence.jpa.dao.MySQLAnyFinder;
import org.apache.syncope.core.persistence.jpa.dao.MySQLJPAAnySearchDAO;
import org.apache.syncope.core.persistence.jpa.dao.repo.MySQLPlainSchemaRepoExtImpl;
import org.apache.syncope.core.persistence.jpa.dao.repo.PlainSchemaRepoExt;
@@ -53,12 +51,6 @@ public EntityFactory entityFactory() {
return new MySQLEntityFactory();
}
- @ConditionalOnMissingBean
- @Bean
- public AnyFinder anyFinder(final @Lazy PlainSchemaDAO plainSchemaDAO, final EntityManager entityManager) {
- return new MySQLAnyFinder(plainSchemaDAO, entityManager);
- }
-
@ConditionalOnMissingBean
@Bean
public AnySearchDAO anySearchDAO(
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/OraclePersistenceContext.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/OraclePersistenceContext.java
index 2d4a7fa11d..ac25ca2f7d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/OraclePersistenceContext.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/OraclePersistenceContext.java
@@ -31,8 +31,6 @@
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.jpa.dao.AnyFinder;
-import org.apache.syncope.core.persistence.jpa.dao.OracleAnyFinder;
import org.apache.syncope.core.persistence.jpa.dao.OracleJPAAnySearchDAO;
import org.apache.syncope.core.persistence.jpa.dao.repo.OraclePlainSchemaRepoExtImpl;
import org.apache.syncope.core.persistence.jpa.dao.repo.PlainSchemaRepoExt;
@@ -53,12 +51,6 @@ public EntityFactory entityFactory() {
return new OracleEntityFactory();
}
- @ConditionalOnMissingBean
- @Bean
- public AnyFinder anyFinder(final @Lazy PlainSchemaDAO plainSchemaDAO, final EntityManager entityManager) {
- return new OracleAnyFinder(plainSchemaDAO, entityManager);
- }
-
@ConditionalOnMissingBean
@Bean
public AnySearchDAO anySearchDAO(
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PGPersistenceContext.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PGPersistenceContext.java
index 8a4f2dfe23..00af19795c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PGPersistenceContext.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PGPersistenceContext.java
@@ -31,8 +31,6 @@
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.jpa.dao.AnyFinder;
-import org.apache.syncope.core.persistence.jpa.dao.PGAnyFinder;
import org.apache.syncope.core.persistence.jpa.dao.PGJPAAnySearchDAO;
import org.apache.syncope.core.persistence.jpa.dao.repo.PGPlainSchemaRepoExtImpl;
import org.apache.syncope.core.persistence.jpa.dao.repo.PlainSchemaRepoExt;
@@ -53,12 +51,6 @@ public EntityFactory entityFactory() {
return new PGEntityFactory();
}
- @ConditionalOnMissingBean
- @Bean
- public AnyFinder anyFinder(final @Lazy PlainSchemaDAO plainSchemaDAO, final EntityManager entityManager) {
- return new PGAnyFinder(plainSchemaDAO, entityManager);
- }
-
@ConditionalOnMissingBean
@Bean
public AnySearchDAO anySearchDAO(
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
index 82abb71e9f..cfa3ce359e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
@@ -88,9 +88,9 @@
import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
import org.apache.syncope.core.persistence.common.CommonPersistenceContext;
import org.apache.syncope.core.persistence.common.RuntimeDomainLoader;
+import org.apache.syncope.core.persistence.common.dao.AnyFinder;
import org.apache.syncope.core.persistence.jpa.content.XMLContentExporter;
import org.apache.syncope.core.persistence.jpa.content.XMLContentLoader;
-import org.apache.syncope.core.persistence.jpa.dao.AnyFinder;
import org.apache.syncope.core.persistence.jpa.dao.JPAAnyMatchDAO;
import org.apache.syncope.core.persistence.jpa.dao.JPAAuditEventDAO;
import org.apache.syncope.core.persistence.jpa.dao.JPABatchDAO;
@@ -371,6 +371,12 @@ protected Class> getRepositoryBaseClass(final RepositoryMetadata metadata) {
};
}
+ @ConditionalOnMissingBean
+ @Bean
+ public AnyFinder anyFinder(final @Lazy PlainSchemaDAO plainSchemaDAO, final @Lazy AnySearchDAO anySearchDAO) {
+ return new AnyFinder(plainSchemaDAO, anySearchDAO);
+ }
+
@ConditionalOnMissingBean
@Bean
public AccessTokenDAO accessTokenDAO(final JpaRepositoryFactory jpaRepositoryFactory) {
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java
index 7574ecdf7e..2e045b69ee 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java
@@ -242,8 +242,11 @@ protected Optional>> getQuery(
or(() -> cond.of(AttrCond.class).
map(attrCond -> {
Pair checked = check(attrCond, svs.anyTypeKind);
- plainSchemas.add(checked.getLeft().getKey());
- return getQuery(attrCond, not, checked, parameters, svs);
+ Pair query = getQuery(attrCond, not, checked, parameters, svs);
+ if (query.getLeft()) {
+ plainSchemas.add(checked.getLeft().getKey());
+ }
+ return query.getRight();
}));
}
@@ -608,9 +611,8 @@ protected AnySearchNode.Leaf fillAttrQuery(
} else {
clause.append('?').append(setParameter(parameters, cond.getExpression()));
}
- // workaround for Oracle DB adding explicit escape, to search for literal _ (underscore)
if (isOracle()) {
- clause.append(" ESCAPE '\\' ");
+ clause.append(" ESCAPE '\\'");
}
} else {
LOG.error("LIKE is only compatible with string or enum schemas");
@@ -679,7 +681,7 @@ protected AnySearchNode.Leaf fillAttrQuery(
: from.alias() + ".schema_id='" + schema.getKey() + "' AND " + clause);
}
- protected AnySearchNode getQuery(
+ protected Pair getQuery(
final AttrCond cond,
final boolean not,
final Pair checked,
@@ -701,9 +703,9 @@ protected AnySearchNode getQuery(
switch (cond.getType()) {
case ISNOTNULL -> {
- return new AnySearchNode.Leaf(
+ return Pair.of(true, new AnySearchNode.Leaf(
sv,
- sv.alias() + ".schema_id='" + checked.getLeft().getKey() + "'");
+ sv.alias() + ".schema_id='" + checked.getLeft().getKey() + "'"));
}
case ISNULL -> {
@@ -713,7 +715,7 @@ protected AnySearchNode getQuery(
append(sv.name()).
append(" WHERE schema_id=").append("'").append(checked.getLeft().getKey()).append("'").
append(')').toString();
- return new AnySearchNode.Leaf(defaultSV(svs), clause);
+ return Pair.of(true, new AnySearchNode.Leaf(defaultSV(svs), clause));
}
default -> {
@@ -743,7 +745,7 @@ protected AnySearchNode getQuery(
not,
parameters);
}
- return node;
+ return Pair.of(true, node);
}
}
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AnyFinder.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AnyFinder.java
deleted file mode 100644
index 8b962e652b..0000000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AnyFinder.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.persistence.jpa.dao;
-
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.Query;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.StringJoiner;
-import java.util.regex.Pattern;
-import org.apache.commons.jexl3.parser.Parser;
-import org.apache.commons.jexl3.parser.ParserConstants;
-import org.apache.commons.jexl3.parser.Token;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.AttrSchemaType;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.transaction.annotation.Transactional;
-
-public abstract class AnyFinder {
-
- protected static final Logger LOG = LoggerFactory.getLogger(AnyFinder.class);
-
- /**
- * Split an attribute value recurring on provided literals/tokens.
- *
- * @param attrValue value to be split
- * @param literals literals/tokens
- * @return split value
- */
- protected static List split(final String attrValue, final List literals) {
- final List attrValues = new ArrayList<>();
-
- if (literals.isEmpty()) {
- attrValues.add(attrValue);
- } else {
- for (String token : attrValue.split(Pattern.quote(literals.get(0)))) {
- if (!token.isEmpty()) {
- attrValues.addAll(split(token, literals.subList(1, literals.size())));
- }
- }
- }
-
- return attrValues;
- }
-
- protected final PlainSchemaDAO plainSchemaDAO;
-
- protected final EntityManager entityManager;
-
- protected AnyFinder(final PlainSchemaDAO plainSchemaDAO, final EntityManager entityManager) {
- this.plainSchemaDAO = plainSchemaDAO;
- this.entityManager = entityManager;
- }
-
- protected String view(final String table) {
- return StringUtils.containsIgnoreCase(table, AnyTypeKind.USER.name())
- ? "user_search"
- : StringUtils.containsIgnoreCase(table, AnyTypeKind.GROUP.name())
- ? "group_search"
- : "anyObject_search";
- }
-
- protected abstract String queryBegin(String table);
-
- protected Pair schemaInfo(final AttrSchemaType schemaType, final boolean ignoreCaseMatch) {
- String key;
- boolean lower = false;
-
- switch (schemaType) {
- case Boolean:
- key = "booleanValue";
- break;
-
- case Date:
- key = "dateValue";
- break;
-
- case Double:
- key = "doubleValue";
- break;
-
- case Long:
- key = "longValue";
- break;
-
- case Binary:
- key = "binaryValue";
- break;
-
- default:
- lower = ignoreCaseMatch;
- key = "stringValue";
- }
-
- return Pair.of(key, lower);
- }
-
- protected abstract String attrValueMatch(
- AnyUtils anyUtils,
- PlainSchema schema,
- PlainAttrValue attrValue,
- boolean ignoreCaseMatch);
-
- protected Object getAttrValue(
- final PlainSchema schema,
- final PlainAttrValue attrValue,
- final boolean ignoreCaseMatch) {
-
- return attrValue.getValue();
- }
-
- protected > List buildResult(final AnyUtils anyUtils, final List