Refactor RSQL Utility - make it singleton and injectable (#2536)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-07-07 17:16:26 +03:00
committed by GitHub
parent 7f97d6f441
commit ea06783fa2
29 changed files with 231 additions and 893 deletions

View File

@@ -19,13 +19,10 @@ import jakarta.persistence.criteria.CriteriaQuery;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder;
import org.springframework.orm.jpa.vendor.Database;
public class HawkbitQlToSql { public class HawkbitQlToSql {
private static final Database DATABASE = Database.H2;
private final EntityManager entityManager; private final EntityManager entityManager;
private final boolean isEclipselink; private final boolean isEclipselink;
@@ -61,16 +58,16 @@ public class HawkbitQlToSql {
final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final RsqlToSpecBuilder rsqlToSpecBuilder) { final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final RsqlToSpecBuilder rsqlToSpecBuilder) {
final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass); final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final RsqlToSpecBuilder defaultRsqlToSpecBuilder = RsqlConfigHolder.getInstance().getRsqlToSpecBuilder(); final RsqlToSpecBuilder defaultRsqlToSpecBuilder = RsqlUtility.getInstance().getRsqlToSpecBuilder();
if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) { if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) {
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder); RsqlUtility.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder);
} }
try { try {
return query.where(RsqlUtility.<A, T> buildRsqlSpecification(rsql, fieldsClass, null, DATABASE) return query.where(RsqlUtility.getInstance().<A, T> buildRsqlSpecification(rsql, fieldsClass)
.toPredicate(query.from(domainClass), cb.createQuery(domainClass), cb)); .toPredicate(query.from(domainClass), cb.createQuery(domainClass), cb));
} finally { } finally {
if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) { if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) {
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(defaultRsqlToSpecBuilder); RsqlUtility.getInstance().setRsqlToSpecBuilder(defaultRsqlToSpecBuilder);
} }
} }
} }

View File

@@ -1,61 +0,0 @@
/**
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.rsql;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
/**
* Helper class providing static access to the RSQL configuration as managed bean.
*/
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
@Getter
@SuppressWarnings("java:S6548") // singleton holder ensures static access to spring resources in some places
public final class RsqlConfigHolder {
private static final RsqlConfigHolder SINGLETON = new RsqlConfigHolder();
public enum RsqlToSpecBuilder {
LEGACY_G1, // legacy RSQL visitor
LEGACY_G2, // G2 RSQL visitor
G3 // G3 RSQL visitor - still experimental / yet default
}
/**
* If RSQL comparison operators shall ignore the case. If ignore case is <code>true</code> "x == ax" will match "x == aX"
*/
@Value("${hawkbit.rsql.ignore-case:true}")
private boolean ignoreCase;
/**
* Declares if the database is case-insensitive, by default assumes <code>false</code>. In case it is case-sensitive and,
* {@link #ignoreCase} is set to <code>true</code> the SQL queries use upper case comparisons to ignore case.
*
* If the database is declared as case-sensitive and ignoreCase is set to <code>false</code> the RSQL queries shall use strict
* syntax - i.e. 'and' instead of 'AND' / 'aND'. Otherwise, the queries would be case-insensitive regarding operators.
*/
@Value("${hawkbit.rsql.case-insensitive-db:false}")
private boolean caseInsensitiveDB;
/**
* @deprecated in favour fixed final visitor / spec builder of G2 RSQL visitor / G3 spec builder. since 0.6.0
*/
@Setter // for tests only
@Deprecated(forRemoval = true, since = "0.6.0")
@Value("${hawkbit.rsql.rsql-to-spec-builder:G3}") //
private RsqlToSpecBuilder rsqlToSpecBuilder;
/**
* @return The holder singleton instance.
*/
public static RsqlConfigHolder getInstance() {
return SINGLETON;
}
}

View File

@@ -9,15 +9,15 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql; package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.G3;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import cz.jirutka.rsql.parser.RSQLParserException; import cz.jirutka.rsql.parser.RSQLParserException;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrLookup;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.RsqlQueryField;
@@ -27,6 +27,9 @@ import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder;
import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy; import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.Database;
@@ -64,8 +67,66 @@ import org.springframework.orm.jpa.vendor.Database;
* $${OVERDUE_TS} would prevent the ${OVERDUE_TS} token from being expanded. * $${OVERDUE_TS} would prevent the ${OVERDUE_TS} token from being expanded.
*/ */
@Slf4j @Slf4j
@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class RsqlUtility { public class RsqlUtility {
private static final RsqlUtility SINGLETON = new RsqlUtility();
public enum RsqlToSpecBuilder {
LEGACY_G1, // legacy RSQL visitor
LEGACY_G2, // G2 RSQL visitor
G3 // G3 RSQL visitor - still experimental / yet default
}
/**
* If RSQL comparison operators shall ignore the case. If ignore case is <code>true</code> "x == ax" will match "x == aX"
*/
@Value("${hawkbit.rsql.ignore-case:true}")
private boolean ignoreCase;
/**
* Declares if the database is case-insensitive, by default assumes <code>false</code>. In case it is case-sensitive and,
* {@link #ignoreCase} is set to <code>true</code> the SQL queries use upper case comparisons to ignore case.
* <p/>
* If the database is declared as case-sensitive and ignoreCase is set to <code>false</code> the RSQL queries shall use strict
* syntax - i.e. 'and' instead of 'AND' / 'aND'. Otherwise, the queries would be case-insensitive regarding operators.
*/
@Value("${hawkbit.rsql.case-insensitive-db:false}")
private boolean caseInsensitiveDB;
/**
* @deprecated in favour fixed final visitor / spec builder of G2 RSQL visitor / G3 spec builder. since 0.6.0
*/
@Setter // for tests only
@Deprecated(forRemoval = true, since = "0.6.0")
@Value("${hawkbit.rsql.rsql-to-spec-builder:G3}") //
private RsqlToSpecBuilder rsqlToSpecBuilder;
private VirtualPropertyReplacer virtualPropertyReplacer;
private Database database;
private EntityManager entityManager;
/**
* @return The holder singleton instance.
*/
public static RsqlUtility getInstance() {
return SINGLETON;
}
@Autowired(required = false)
void setVirtualPropertyReplacer(final VirtualPropertyReplacer virtualPropertyReplacer) {
this.virtualPropertyReplacer = virtualPropertyReplacer;
}
@Autowired
void setDatabase(final JpaProperties jpaProperties) {
database = jpaProperties.getDatabase();
}
@Autowired
void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
/** /**
* Builds a JPA {@link Specification} which corresponds with the given RSQL query. The specification can be used to filter for JPA entities * Builds a JPA {@link Specification} which corresponds with the given RSQL query. The specification can be used to filter for JPA entities
@@ -73,25 +134,16 @@ public final class RsqlUtility {
* *
* @param rsql the rsql query to be parsed * @param rsql the rsql query to be parsed
* @param rsqlQueryFieldType the enum class type which implements the {@link RsqlQueryField} * @param rsqlQueryFieldType the enum class type which implements the {@link RsqlQueryField}
* @param virtualPropertyReplacer holds the logic how the known macros have to be resolved; may be <code>null</code>
* @param database database in use
* @return a specification which can be used with JPA * @return a specification which can be used with JPA
* @throws RSQLParameterUnsupportedFieldException if a field in the RSQL string is used but not provided by the * @throws RSQLParameterUnsupportedFieldException if a field in the RSQL string is used but not provided by the
* given {@code fieldNameProvider} * given {@code fieldNameProvider}
* @throws RSQLParameterSyntaxException if the RSQL syntax is wrong * @throws RSQLParameterSyntaxException if the RSQL syntax is wrong
*/ */
public static <A extends Enum<A> & RsqlQueryField, T> Specification<T> buildRsqlSpecification( public <A extends Enum<A> & RsqlQueryField, T> Specification<T> buildRsqlSpecification(
final String rsql, final Class<A> rsqlQueryFieldType, final String rsql, final Class<A> rsqlQueryFieldType) {
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) { if (rsqlToSpecBuilder == RsqlToSpecBuilder.G3) {
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == G3) { return new SpecificationBuilder<T>(virtualPropertyReplacer, !caseInsensitiveDB && ignoreCase, database)
return new SpecificationBuilder<T>( .specification(RsqlParser.parse(caseInsensitiveDB || ignoreCase ? rsql.toLowerCase() : rsql, rsqlQueryFieldType));
virtualPropertyReplacer,
!RsqlConfigHolder.getInstance().isCaseInsensitiveDB() && RsqlConfigHolder.getInstance().isIgnoreCase(),
database)
.specification(RsqlParser.parse(
RsqlConfigHolder.getInstance().isCaseInsensitiveDB() || RsqlConfigHolder.getInstance().isIgnoreCase()
? rsql.toLowerCase() : rsql,
rsqlQueryFieldType));
} else { } else {
return new SpecificationBuilderLegacy<A, T>(rsqlQueryFieldType, virtualPropertyReplacer, database).specification(rsql); return new SpecificationBuilderLegacy<A, T>(rsqlQueryFieldType, virtualPropertyReplacer, database).specification(rsql);
} }
@@ -101,18 +153,16 @@ public final class RsqlUtility {
* Validates the RSQL string * Validates the RSQL string
* *
* @param rsql RSQL string to validate * @param rsql RSQL string to validate
* @param rsqlQueryFieldType * @param rsqlQueryFieldType the enum class type which implements the {@link RsqlQueryField}
* @param jpaType the JPA entity type to validate against
* @throws RSQLParserException if RSQL syntax is invalid * @throws RSQLParserException if RSQL syntax is invalid
* @throws RSQLParameterUnsupportedFieldException if RSQL key is not allowed * @throws RSQLParameterUnsupportedFieldException if RSQL key is not allowed
*/ */
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
public static <A extends Enum<A> & RsqlQueryField> void validateRsqlFor( public <A extends Enum<A> & RsqlQueryField> void validateRsqlFor(
final String rsql, final Class<A> rsqlQueryFieldType, final String rsql, final Class<A> rsqlQueryFieldType, final Class<?> jpaType) {
final Class<?> jpaType,
final VirtualPropertyReplacer virtualPropertyReplacer, final EntityManager entityManager) {
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<?> criteriaQuery = criteriaBuilder.createQuery(jpaType); final CriteriaQuery<?> criteriaQuery = criteriaBuilder.createQuery(jpaType);
buildRsqlSpecification(rsql, rsqlQueryFieldType, virtualPropertyReplacer, null) buildRsqlSpecification(rsql, rsqlQueryFieldType).toPredicate(criteriaQuery.from((Class) jpaType), criteriaQuery, criteriaBuilder);
.toPredicate(criteriaQuery.from((Class) jpaType), criteriaQuery, criteriaBuilder);
} }
} }

View File

@@ -10,7 +10,7 @@
package org.eclipse.hawkbit.repository.jpa.rsql.legacy; package org.eclipse.hawkbit.repository.jpa.rsql.legacy;
import static org.eclipse.hawkbit.repository.jpa.rsql.legacy.AbstractRSQLVisitor.OPERATORS; import static org.eclipse.hawkbit.repository.jpa.rsql.legacy.AbstractRSQLVisitor.OPERATORS;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import java.util.List; import java.util.List;
@@ -24,7 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder; import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.Database;
@@ -50,14 +50,14 @@ public class SpecificationBuilderLegacy<A extends Enum<A> & RsqlQueryField, T> {
public Specification<T> specification(final String rsql) { public Specification<T> specification(final String rsql) {
return (root, query, cb) -> { return (root, query, cb) -> {
final RsqlConfigHolder rsqlConfigHolder = RsqlConfigHolder.getInstance(); final RsqlUtility rsqlUtility = RsqlUtility.getInstance();
final Node rootNode = parseRsql(rsql, rsqlConfigHolder); final Node rootNode = parseRsql(rsql, rsqlUtility);
query.distinct(true); query.distinct(true);
final boolean ensureIgnoreCase = !rsqlConfigHolder.isCaseInsensitiveDB() && rsqlConfigHolder.isIgnoreCase(); final boolean ensureIgnoreCase = !rsqlUtility.isCaseInsensitiveDB() && rsqlUtility.isIgnoreCase();
final RSQLVisitor<List<Predicate>, String> jpqQueryRSQLVisitor = final RSQLVisitor<List<Predicate>, String> jpqQueryRSQLVisitor =
rsqlConfigHolder.getRsqlToSpecBuilder() == LEGACY_G1 rsqlUtility.getRsqlToSpecBuilder() == LEGACY_G1
? new JpaQueryRsqlVisitor<>(root, cb, rsqlQueryFieldType, virtualPropertyReplacer, database, query, ensureIgnoreCase) ? new JpaQueryRsqlVisitor<>(root, cb, rsqlQueryFieldType, virtualPropertyReplacer, database, query, ensureIgnoreCase)
: new JpaQueryRsqlVisitorG2<>(rsqlQueryFieldType, root, query, cb, database, virtualPropertyReplacer, ensureIgnoreCase); : new JpaQueryRsqlVisitorG2<>(rsqlQueryFieldType, root, query, cb, database, virtualPropertyReplacer, ensureIgnoreCase);
final List<Predicate> accept = rootNode.accept(jpqQueryRSQLVisitor); final List<Predicate> accept = rootNode.accept(jpqQueryRSQLVisitor);
@@ -70,10 +70,10 @@ public class SpecificationBuilderLegacy<A extends Enum<A> & RsqlQueryField, T> {
}; };
} }
private static Node parseRsql(final String rsql, final RsqlConfigHolder rsqlConfigHolder) { private static Node parseRsql(final String rsql, final RsqlUtility rsqlUtility) {
log.debug("Parsing rsql string {}", rsql); log.debug("Parsing rsql string {}", rsql);
try { try {
return new RSQLParser(OPERATORS).parse(rsqlConfigHolder.isCaseInsensitiveDB() || rsqlConfigHolder.isIgnoreCase() ? rsql.toLowerCase() : rsql); return new RSQLParser(OPERATORS).parse(rsqlUtility.isCaseInsensitiveDB() || rsqlUtility.isIgnoreCase() ? rsql.toLowerCase() : rsql);
} catch (final IllegalArgumentException e) { } catch (final IllegalArgumentException e) {
throw new RSQLParameterSyntaxException("RSQL filter must not be null", e); throw new RSQLParameterSyntaxException("RSQL filter must not be null", e);
} catch (final RSQLParserException e) { } catch (final RSQLParserException e) {

View File

@@ -7,7 +7,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;

View File

@@ -7,7 +7,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;

View File

@@ -7,10 +7,10 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -18,9 +18,9 @@ import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder;
import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy; import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.Database;
@@ -32,12 +32,12 @@ class SpecificationBuilderLegacyTest extends SpecificationBuilderTest {
private final SpecificationBuilderLegacy<RootField, Root> builder = new SpecificationBuilderLegacy<>(RootField.class, null, Database.H2); private final SpecificationBuilderLegacy<RootField, Root> builder = new SpecificationBuilderLegacy<>(RootField.class, null, Database.H2);
private static void runWithRsqlToSpecBuilder(final Runnable runnable, final RsqlToSpecBuilder rsqlToSpecBuilder) { private static void runWithRsqlToSpecBuilder(final Runnable runnable, final RsqlToSpecBuilder rsqlToSpecBuilder) {
final RsqlToSpecBuilder defaultBuilder = RsqlConfigHolder.getInstance().getRsqlToSpecBuilder(); final RsqlToSpecBuilder defaultBuilder = RsqlUtility.getInstance().getRsqlToSpecBuilder();
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder); RsqlUtility.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder);
try { try {
runnable.run(); runnable.run();
} finally { } finally {
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(defaultBuilder); RsqlUtility.getInstance().setRsqlToSpecBuilder(defaultBuilder);
} }
} }

View File

@@ -7,12 +7,12 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.G3; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.G3;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -22,11 +22,9 @@ import java.util.stream.StreamSupport;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.jpa.ql.EntityMatcher;
import org.eclipse.hawkbit.repository.jpa.ql.utils.HawkbitQlToSql; import org.eclipse.hawkbit.repository.jpa.ql.utils.HawkbitQlToSql;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParser; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParser;
import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.SpringBootConfiguration;
@@ -491,8 +489,8 @@ class SpecificationBuilderTest {
return builder.specification(RsqlParser.parse(rsql)); return builder.specification(RsqlParser.parse(rsql));
} }
private static RsqlConfigHolder.RsqlToSpecBuilder getRsqlToSpecBuilder() { private static RsqlUtility.RsqlToSpecBuilder getRsqlToSpecBuilder() {
return RsqlConfigHolder.getInstance().getRsqlToSpecBuilder(); return RsqlUtility.getInstance().getRsqlToSpecBuilder();
} }
@SpringBootConfiguration @SpringBootConfiguration

View File

@@ -7,16 +7,13 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType; import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -7,7 +7,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;

View File

@@ -7,7 +7,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;

View File

@@ -7,7 +7,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql.sa; package org.eclipse.hawkbit.repository.jpa.ql;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;

View File

@@ -154,7 +154,7 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder; import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.eclipse.hawkbit.security.SecurityTokenGenerator;
@@ -538,15 +538,13 @@ public class RepositoryApplicationConfiguration {
final TargetRepository targetRepository, final TargetRepository targetRepository,
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository, final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement tenantConfigurationManagement, final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement tenantConfigurationManagement,
final VirtualPropertyReplacer virtualPropertyReplacer, final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleRepository softwareModuleRepository,
final DistributionSetTagRepository distributionSetTagRepository, final DistributionSetTagRepository distributionSetTagRepository, final RepositoryProperties repositoryProperties) {
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
return new JpaDistributionSetManagement(entityManager, distributionSetRepository, distributionSetTagManagement, return new JpaDistributionSetManagement(entityManager, distributionSetRepository, distributionSetTagManagement,
systemManagement, distributionSetTypeManagement, quotaManagement, systemManagement, distributionSetTypeManagement, quotaManagement,
targetRepository, targetFilterQueryRepository, actionRepository, targetRepository, targetFilterQueryRepository, actionRepository,
TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement), TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement),
virtualPropertyReplacer, softwareModuleRepository, distributionSetTagRepository, softwareModuleRepository, distributionSetTagRepository, repositoryProperties);
properties.getDatabase(), repositoryProperties);
} }
/** /**
@@ -560,11 +558,9 @@ public class RepositoryApplicationConfiguration {
final DistributionSetTypeRepository distributionSetTypeRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository, final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
final QuotaManagement quotaManagement) { final QuotaManagement quotaManagement) {
return new JpaDistributionSetTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository, return new JpaDistributionSetTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
distributionSetRepository, targetTypeRepository, virtualPropertyReplacer, properties.getDatabase(), distributionSetRepository, targetTypeRepository, quotaManagement);
quotaManagement);
} }
/** /**
@@ -576,10 +572,8 @@ public class RepositoryApplicationConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
TargetTypeManagement targetTypeManagement(final TargetTypeRepository targetTypeRepository, TargetTypeManagement targetTypeManagement(final TargetTypeRepository targetTypeRepository,
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository, final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
final QuotaManagement quotaManagement) { final QuotaManagement quotaManagement) {
return new JpaTargetTypeManagement(targetTypeRepository, targetRepository, distributionSetTypeRepository, return new JpaTargetTypeManagement(targetTypeRepository, targetRepository, distributionSetTypeRepository, quotaManagement);
virtualPropertyReplacer, properties.getDatabase(), quotaManagement);
} }
/** /**
@@ -618,18 +612,16 @@ public class RepositoryApplicationConfiguration {
*/ */
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
TargetManagement targetManagement(final EntityManager entityManager, final QuotaManagement quotaManagement, TargetManagement targetManagement(
final EntityManager entityManager, final QuotaManagement quotaManagement,
final TargetRepository targetRepository, final TargetRepository targetRepository,
final RolloutGroupRepository rolloutGroupRepository, final RolloutGroupRepository rolloutGroupRepository,
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetFilterQueryRepository targetFilterQueryRepository,
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository, final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
final TenantAware tenantAware, final TenantAware tenantAware, final DistributionSetManagement distributionSetManagement) {
final VirtualPropertyReplacer virtualPropertyReplacer,
final JpaProperties properties, final DistributionSetManagement distributionSetManagement) {
return new JpaTargetManagement(entityManager, distributionSetManagement, quotaManagement, targetRepository, return new JpaTargetManagement(entityManager, distributionSetManagement, quotaManagement, targetRepository,
targetTypeRepository, rolloutGroupRepository, targetFilterQueryRepository, targetTypeRepository, rolloutGroupRepository, targetFilterQueryRepository,
targetTagRepository, tenantAware, virtualPropertyReplacer, targetTagRepository, tenantAware);
properties.getDatabase());
} }
/** /**
@@ -637,25 +629,20 @@ public class RepositoryApplicationConfiguration {
* *
* @param targetFilterQueryRepository holding {@link TargetFilterQuery} entities * @param targetFilterQueryRepository holding {@link TargetFilterQuery} entities
* @param targetManagement managing {@link Target} entities * @param targetManagement managing {@link Target} entities
* @param virtualPropertyReplacer for RSQL handling
* @param distributionSetManagement for auto assign DS access * @param distributionSetManagement for auto assign DS access
* @param quotaManagement to access quotas * @param quotaManagement to access quotas
* @param properties JPA properties
* @return a new {@link TargetFilterQueryManagement} * @return a new {@link TargetFilterQueryManagement}
*/ */
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
TargetFilterQueryManagement targetFilterQueryManagement( TargetFilterQueryManagement targetFilterQueryManagement(
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetManagement targetManagement, final TargetFilterQueryRepository targetFilterQueryRepository, final TargetManagement targetManagement,
final VirtualPropertyReplacer virtualPropertyReplacer,
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement, final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
final JpaProperties properties, final TenantConfigurationManagement tenantConfigurationManagement, final TenantConfigurationManagement tenantConfigurationManagement, final RepositoryProperties repositoryProperties,
final RepositoryProperties repositoryProperties, final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware) {
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware,
final EntityManager entityManager) {
return new JpaTargetFilterQueryManagement(targetFilterQueryRepository, targetManagement, return new JpaTargetFilterQueryManagement(targetFilterQueryRepository, targetManagement,
virtualPropertyReplacer, distributionSetManagement, quotaManagement, properties.getDatabase(), distributionSetManagement, quotaManagement, tenantConfigurationManagement, repositoryProperties,
tenantConfigurationManagement, repositoryProperties, systemSecurityContext, contextAware, auditorAware, entityManager); systemSecurityContext, contextAware, auditorAware);
} }
/** /**
@@ -665,11 +652,8 @@ public class RepositoryApplicationConfiguration {
*/ */
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
TargetTagManagement targetTagManagement(final TargetTagRepository targetTagRepository, TargetTagManagement targetTagManagement(final TargetTagRepository targetTagRepository) {
final VirtualPropertyReplacer virtualPropertyReplacer, return new JpaTargetTagManagement(targetTagRepository);
final JpaProperties properties) {
return new JpaTargetTagManagement(targetTagRepository, virtualPropertyReplacer,
properties.getDatabase());
} }
/** /**
@@ -681,10 +665,9 @@ public class RepositoryApplicationConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
DistributionSetTagManagement distributionSetTagManagement( DistributionSetTagManagement distributionSetTagManagement(
final DistributionSetTagRepository distributionSetTagRepository, final DistributionSetTagRepository distributionSetTagRepository,
final DistributionSetRepository distributionSetRepository, final DistributionSetRepository distributionSetRepository) {
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
return new JpaDistributionSetTagManagement( return new JpaDistributionSetTagManagement(
distributionSetTagRepository, distributionSetRepository, virtualPropertyReplacer, properties.getDatabase()); distributionSetTagRepository, distributionSetRepository);
} }
/** /**
@@ -699,13 +682,9 @@ public class RepositoryApplicationConfiguration {
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleRepository softwareModuleRepository,
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository, final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider, final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement, final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
final VirtualPropertyReplacer virtualPropertyReplacer,
final JpaProperties properties) {
return new JpaSoftwareModuleManagement(entityManager, distributionSetRepository, softwareModuleRepository, return new JpaSoftwareModuleManagement(entityManager, distributionSetRepository, softwareModuleRepository,
softwareModuleMetadataRepository, softwareModuleTypeRepository, auditorProvider, artifactManagement, softwareModuleMetadataRepository, softwareModuleTypeRepository, auditorProvider, artifactManagement, quotaManagement);
quotaManagement, virtualPropertyReplacer,
properties.getDatabase());
} }
/** /**
@@ -718,11 +697,8 @@ public class RepositoryApplicationConfiguration {
SoftwareModuleTypeManagement softwareModuleTypeManagement( SoftwareModuleTypeManagement softwareModuleTypeManagement(
final DistributionSetTypeRepository distributionSetTypeRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final SoftwareModuleRepository softwareModuleRepository) {
final SoftwareModuleRepository softwareModuleRepository, return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository, softwareModuleRepository);
final JpaProperties properties) {
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
virtualPropertyReplacer, softwareModuleRepository, properties.getDatabase());
} }
@Bean @Bean
@@ -765,14 +741,12 @@ public class RepositoryApplicationConfiguration {
final TenantConfigurationManagement tenantConfigurationManagement, final TenantConfigurationManagement tenantConfigurationManagement,
final QuotaManagement quotaManagement, final QuotaManagement quotaManagement,
final AfterTransactionCommitExecutor afterCommit, final AfterTransactionCommitExecutor afterCommit,
final VirtualPropertyReplacer virtualPropertyReplacer, final SystemSecurityContext systemSecurityContext, final ContextAware contextAware,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final JpaProperties properties,
final RepositoryProperties repositoryProperties) { final RepositoryProperties repositoryProperties) {
return new JpaRolloutManagement(rolloutRepository, rolloutGroupRepository, rolloutApprovalStrategy, return new JpaRolloutManagement(rolloutRepository, rolloutGroupRepository, rolloutApprovalStrategy,
startNextRolloutGroupAction, rolloutStatusCache, actionRepository, targetManagement, startNextRolloutGroupAction, rolloutStatusCache, actionRepository, targetManagement,
distributionSetManagement, tenantConfigurationManagement, quotaManagement, afterCommit, distributionSetManagement, tenantConfigurationManagement, quotaManagement, afterCommit,
virtualPropertyReplacer, systemSecurityContext, contextAware, properties.getDatabase(), systemSecurityContext, contextAware, repositoryProperties);
repositoryProperties);
} }
/** /**
@@ -798,11 +772,9 @@ public class RepositoryApplicationConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
RolloutGroupManagement rolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository, RolloutGroupManagement rolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
final RolloutRepository rolloutRepository, final ActionRepository actionRepository, final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
final TargetRepository targetRepository, final EntityManager entityManager, final TargetRepository targetRepository, final EntityManager entityManager, final RolloutStatusCache rolloutStatusCache) {
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
final JpaProperties properties) {
return new JpaRolloutGroupManagement(rolloutGroupRepository, rolloutRepository, actionRepository, return new JpaRolloutGroupManagement(rolloutGroupRepository, rolloutRepository, actionRepository,
targetRepository, entityManager, virtualPropertyReplacer, rolloutStatusCache, properties.getDatabase()); targetRepository, entityManager, rolloutStatusCache);
} }
/** /**
@@ -816,14 +788,13 @@ public class RepositoryApplicationConfiguration {
final ActionRepository actionRepository, final ActionRepository actionRepository,
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository, final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider, final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
final AfterTransactionCommitExecutor afterCommit, final AfterTransactionCommitExecutor afterCommit, final PlatformTransactionManager txManager,
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware, final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
final JpaProperties properties, final RepositoryProperties repositoryProperties) { final JpaProperties properties, final RepositoryProperties repositoryProperties) {
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement, targetRepository, actionStatusRepository, return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement, targetRepository, actionStatusRepository,
auditorProvider, auditorProvider,
afterCommit, virtualPropertyReplacer, txManager, tenantConfigurationManagement, afterCommit, txManager, tenantConfigurationManagement,
quotaManagement, systemSecurityContext, tenantAware, auditorAware, properties.getDatabase(), repositoryProperties); quotaManagement, systemSecurityContext, tenantAware, auditorAware, properties.getDatabase(), repositoryProperties);
} }
@@ -1010,13 +981,13 @@ public class RepositoryApplicationConfiguration {
} }
/** /**
* Obtains the {@link RsqlConfigHolder} bean. * Register the {@link RsqlUtility} bean to force Spring to inject values and auto-wired fields.
* *
* @return The {@link RsqlConfigHolder} singleton. * @return The {@link RsqlUtility} singleton.
*/ */
@Bean @Bean
RsqlConfigHolder rsqlConfigHolder() { RsqlUtility rsqlUtility() {
return RsqlConfigHolder.getInstance(); return RsqlUtility.getInstance();
} }
/** /**

View File

@@ -86,7 +86,6 @@ import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TargetWithActionType; import org.eclipse.hawkbit.repository.model.TargetWithActionType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.eclipse.hawkbit.utils.TenantConfigHelper;
@@ -150,7 +149,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
private final DistributionSetManagement distributionSetManagement; private final DistributionSetManagement distributionSetManagement;
private final TargetRepository targetRepository; private final TargetRepository targetRepository;
private final AuditorAware<String> auditorProvider; private final AuditorAware<String> auditorProvider;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final PlatformTransactionManager txManager; private final PlatformTransactionManager txManager;
private final OnlineDsAssignmentStrategy onlineDsAssignmentStrategy; private final OnlineDsAssignmentStrategy onlineDsAssignmentStrategy;
private final OfflineDsAssignmentStrategy offlineDsAssignmentStrategy; private final OfflineDsAssignmentStrategy offlineDsAssignmentStrategy;
@@ -166,8 +164,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
final EntityManager entityManager, final ActionRepository actionRepository, final EntityManager entityManager, final ActionRepository actionRepository,
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository, final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider, final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
final AfterTransactionCommitExecutor afterCommit, final AfterTransactionCommitExecutor afterCommit, final PlatformTransactionManager txManager,
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware, final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
final Database database, final RepositoryProperties repositoryProperties) { final Database database, final RepositoryProperties repositoryProperties) {
@@ -176,7 +173,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
this.distributionSetManagement = distributionSetManagement; this.distributionSetManagement = distributionSetManagement;
this.targetRepository = targetRepository; this.targetRepository = targetRepository;
this.auditorProvider = auditorProvider; this.auditorProvider = auditorProvider;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.txManager = txManager; this.txManager = txManager;
onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, afterCommit, onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, afterCommit,
actionRepository, actionStatusRepository, quotaManagement, this::isMultiAssignmentsEnabled, actionRepository, actionStatusRepository, quotaManagement, this::isMultiAssignmentsEnabled,
@@ -274,7 +270,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
assertTargetReadAllowed(controllerId); assertTargetReadAllowed(controllerId);
final List<Specification<JpaAction>> specList = Arrays.asList( final List<Specification<JpaAction>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class),
ActionSpecifications.byTargetControllerId(controllerId)); ActionSpecifications.byTargetControllerId(controllerId));
return JpaManagementHelper.countBySpec(actionRepository, specList); return JpaManagementHelper.countBySpec(actionRepository, specList);
@@ -287,8 +283,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override @Override
public long countActions(final String rsql) { public long countActions(final String rsql) {
final List<Specification<JpaAction>> specList = List.of( final List<Specification<JpaAction>> specList = List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class));
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database));
return JpaManagementHelper.countBySpec(actionRepository, specList); return JpaManagementHelper.countBySpec(actionRepository, specList);
} }
@@ -312,8 +307,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override @Override
public Slice<Action> findActions(final String rsql, final Pageable pageable) { public Slice<Action> findActions(final String rsql, final Pageable pageable) {
final List<Specification<JpaAction>> specList = List.of( final List<Specification<JpaAction>> specList = List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class));
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database));
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, specList, pageable); return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, specList, pageable);
} }
@@ -322,7 +316,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
assertTargetReadAllowed(controllerId); assertTargetReadAllowed(controllerId);
final List<Specification<JpaAction>> specList = Arrays.asList( final List<Specification<JpaAction>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class),
ActionSpecifications.byTargetControllerId(controllerId)); ActionSpecifications.byTargetControllerId(controllerId));
return JpaManagementHelper.findAllWithCountBySpec(actionRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(actionRepository, specList, pageable);

View File

@@ -73,14 +73,12 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Statistic; import org.eclipse.hawkbit.repository.model.Statistic;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -105,10 +103,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
private final TargetFilterQueryRepository targetFilterQueryRepository; private final TargetFilterQueryRepository targetFilterQueryRepository;
private final ActionRepository actionRepository; private final ActionRepository actionRepository;
private final TenantConfigHelper tenantConfigHelper; private final TenantConfigHelper tenantConfigHelper;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final SoftwareModuleRepository softwareModuleRepository; private final SoftwareModuleRepository softwareModuleRepository;
private final DistributionSetTagRepository distributionSetTagRepository; private final DistributionSetTagRepository distributionSetTagRepository;
private final Database database;
private final RepositoryProperties repositoryProperties; private final RepositoryProperties repositoryProperties;
@SuppressWarnings("java:S107") @SuppressWarnings("java:S107")
@@ -120,10 +116,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
final TargetRepository targetRepository, final TargetRepository targetRepository,
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository, final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
final TenantConfigHelper tenantConfigHelper, final TenantConfigHelper tenantConfigHelper,
final VirtualPropertyReplacer virtualPropertyReplacer,
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleRepository softwareModuleRepository,
final DistributionSetTagRepository distributionSetTagRepository, final DistributionSetTagRepository distributionSetTagRepository,
final Database database,
final RepositoryProperties repositoryProperties) { final RepositoryProperties repositoryProperties) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.distributionSetRepository = distributionSetRepository; this.distributionSetRepository = distributionSetRepository;
@@ -135,10 +129,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
this.targetFilterQueryRepository = targetFilterQueryRepository; this.targetFilterQueryRepository = targetFilterQueryRepository;
this.actionRepository = actionRepository; this.actionRepository = actionRepository;
this.tenantConfigHelper = tenantConfigHelper; this.tenantConfigHelper = tenantConfigHelper;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.softwareModuleRepository = softwareModuleRepository; this.softwareModuleRepository = softwareModuleRepository;
this.distributionSetTagRepository = distributionSetTagRepository; this.distributionSetTagRepository = distributionSetTagRepository;
this.database = database;
this.repositoryProperties = repositoryProperties; this.repositoryProperties = repositoryProperties;
} }
@@ -282,7 +274,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override @Override
public Page<DistributionSet> findByRsql(final String rsql, final Pageable pageable) { public Page<DistributionSet> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of( return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, DistributionSetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class),
DistributionSetSpecification.isNotDeleted()), pageable); DistributionSetSpecification.isNotDeleted()), pageable);
} }
@@ -551,8 +543,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
assertDsTagExists(tagId); assertDsTagExists(tagId);
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of( return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, DistributionSetFields.class, virtualPropertyReplacer, RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class),
database),
DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isNotDeleted()), pageable); DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isNotDeleted()), pageable);
} }

View File

@@ -33,13 +33,11 @@ import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTagSpeci
import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -54,17 +52,12 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
private final DistributionSetTagRepository distributionSetTagRepository; private final DistributionSetTagRepository distributionSetTagRepository;
private final DistributionSetRepository distributionSetRepository; private final DistributionSetRepository distributionSetRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
public JpaDistributionSetTagManagement( public JpaDistributionSetTagManagement(
final DistributionSetTagRepository distributionSetTagRepository, final DistributionSetTagRepository distributionSetTagRepository,
final DistributionSetRepository distributionSetRepository, final DistributionSetRepository distributionSetRepository) {
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
this.distributionSetTagRepository = distributionSetTagRepository; this.distributionSetTagRepository = distributionSetTagRepository;
this.distributionSetRepository = distributionSetRepository; this.distributionSetRepository = distributionSetRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
} }
@Override @Override
@@ -155,8 +148,7 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
@Override @Override
public Page<DistributionSetTag> findByRsql(final String rsql, final Pageable pageable) { public Page<DistributionSetTag> findByRsql(final String rsql, final Pageable pageable) {
final Specification<JpaDistributionSetTag> spec = RsqlUtility.buildRsqlSpecification( final Specification<JpaDistributionSetTag> spec = RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetTagFields.class);
rsql, DistributionSetTagFields.class, virtualPropertyReplacer, database);
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, Collections.singletonList(spec), pageable); return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, Collections.singletonList(spec), pageable);
} }

View File

@@ -44,12 +44,10 @@ import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpec
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -67,22 +65,17 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
private final SoftwareModuleTypeRepository softwareModuleTypeRepository; private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
private final DistributionSetRepository distributionSetRepository; private final DistributionSetRepository distributionSetRepository;
private final TargetTypeRepository targetTypeRepository; private final TargetTypeRepository targetTypeRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
private final QuotaManagement quotaManagement; private final QuotaManagement quotaManagement;
public JpaDistributionSetTypeManagement( public JpaDistributionSetTypeManagement(
final DistributionSetTypeRepository distributionSetTypeRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository, final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
final QuotaManagement quotaManagement) { final QuotaManagement quotaManagement) {
this.distributionSetTypeRepository = distributionSetTypeRepository; this.distributionSetTypeRepository = distributionSetTypeRepository;
this.softwareModuleTypeRepository = softwareModuleTypeRepository; this.softwareModuleTypeRepository = softwareModuleTypeRepository;
this.distributionSetRepository = distributionSetRepository; this.distributionSetRepository = distributionSetRepository;
this.targetTypeRepository = targetTypeRepository; this.targetTypeRepository = targetTypeRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
this.quotaManagement = quotaManagement; this.quotaManagement = quotaManagement;
} }
@@ -198,7 +191,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
@Override @Override
public Page<DistributionSetType> findByRsql(final String rsql, final Pageable pageable) { public Page<DistributionSetType> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, List.of( return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, DistributionSetTypeFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetTypeFields.class),
DistributionSetTypeSpecification.isNotDeleted()), pageable); DistributionSetTypeSpecification.isNotDeleted()), pageable);
} }

View File

@@ -48,12 +48,10 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -70,24 +68,18 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
private final ActionRepository actionRepository; private final ActionRepository actionRepository;
private final TargetRepository targetRepository; private final TargetRepository targetRepository;
private final EntityManager entityManager; private final EntityManager entityManager;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final RolloutStatusCache rolloutStatusCache; private final RolloutStatusCache rolloutStatusCache;
private final Database database;
@SuppressWarnings("java:S107") @SuppressWarnings("java:S107")
public JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository, public JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
final RolloutRepository rolloutRepository, final ActionRepository actionRepository, final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
final TargetRepository targetRepository, final EntityManager entityManager, final TargetRepository targetRepository, final EntityManager entityManager, final RolloutStatusCache rolloutStatusCache) {
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
final Database database) {
this.rolloutGroupRepository = rolloutGroupRepository; this.rolloutGroupRepository = rolloutGroupRepository;
this.rolloutRepository = rolloutRepository; this.rolloutRepository = rolloutRepository;
this.actionRepository = actionRepository; this.actionRepository = actionRepository;
this.targetRepository = targetRepository; this.targetRepository = targetRepository;
this.entityManager = entityManager; this.entityManager = entityManager;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.rolloutStatusCache = rolloutStatusCache; this.rolloutStatusCache = rolloutStatusCache;
this.database = database;
} }
@Override @Override
@@ -122,8 +114,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId); throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
final List<Specification<JpaRolloutGroup>> specList = Arrays.asList( final List<Specification<JpaRolloutGroup>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, RolloutGroupFields.class, virtualPropertyReplacer, RsqlUtility.getInstance().buildRsqlSpecification(rsql, RolloutGroupFields.class),
database),
(root, query, cb) -> cb.equal(root.get(JpaRolloutGroup_.rollout).get(AbstractJpaBaseEntity_.id), rolloutId)); (root, query, cb) -> cb.equal(root.get(JpaRolloutGroup_.rollout).get(AbstractJpaBaseEntity_.id), rolloutId));
return JpaManagementHelper.findAllWithCountBySpec(rolloutGroupRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(rolloutGroupRepository, specList, pageable);
@@ -189,7 +180,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId); throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
final List<Specification<JpaTarget>> specList = Arrays.asList( final List<Specification<JpaTarget>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
(root, query, cb) -> { (root, query, cb) -> {
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup); final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup);
return cb.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup).get(AbstractJpaBaseEntity_.id), rolloutGroupId); return cb.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup).get(AbstractJpaBaseEntity_.id), rolloutGroupId);

View File

@@ -78,7 +78,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroupsValidation;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -86,7 +85,6 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
@@ -120,10 +118,8 @@ public class JpaRolloutManagement implements RolloutManagement {
private final TenantConfigurationManagement tenantConfigurationManagement; private final TenantConfigurationManagement tenantConfigurationManagement;
private final QuotaManagement quotaManagement; private final QuotaManagement quotaManagement;
private final AfterTransactionCommitExecutor afterCommit; private final AfterTransactionCommitExecutor afterCommit;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final SystemSecurityContext systemSecurityContext; private final SystemSecurityContext systemSecurityContext;
private final ContextAware contextAware; private final ContextAware contextAware;
private final Database database;
private final RepositoryProperties repositoryProperties; private final RepositoryProperties repositoryProperties;
@SuppressWarnings("java:S107") @SuppressWarnings("java:S107")
@@ -139,8 +135,7 @@ public class JpaRolloutManagement implements RolloutManagement {
final TenantConfigurationManagement tenantConfigurationManagement, final TenantConfigurationManagement tenantConfigurationManagement,
final QuotaManagement quotaManagement, final QuotaManagement quotaManagement,
final AfterTransactionCommitExecutor afterCommit, final AfterTransactionCommitExecutor afterCommit,
final VirtualPropertyReplacer virtualPropertyReplacer, final SystemSecurityContext systemSecurityContext, final ContextAware contextAware,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final Database database,
final RepositoryProperties repositoryProperties) { final RepositoryProperties repositoryProperties) {
this.rolloutRepository = rolloutRepository; this.rolloutRepository = rolloutRepository;
this.rolloutGroupRepository = rolloutGroupRepository; this.rolloutGroupRepository = rolloutGroupRepository;
@@ -153,10 +148,8 @@ public class JpaRolloutManagement implements RolloutManagement {
this.tenantConfigurationManagement = tenantConfigurationManagement; this.tenantConfigurationManagement = tenantConfigurationManagement;
this.quotaManagement = quotaManagement; this.quotaManagement = quotaManagement;
this.afterCommit = afterCommit; this.afterCommit = afterCommit;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.systemSecurityContext = systemSecurityContext; this.systemSecurityContext = systemSecurityContext;
this.contextAware = contextAware; this.contextAware = contextAware;
this.database = database;
this.repositoryProperties = repositoryProperties; this.repositoryProperties = repositoryProperties;
} }
@@ -273,7 +266,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override @Override
public Page<Rollout> findByRsql(final String rsql, final boolean deleted, final Pageable pageable) { public Page<Rollout> findByRsql(final String rsql, final boolean deleted, final Pageable pageable) {
final List<Specification<JpaRollout>> specList = List.of( final List<Specification<JpaRollout>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, RolloutFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, RolloutFields.class),
RolloutSpecification.isDeleted(deleted, pageable.getSort())); RolloutSpecification.isDeleted(deleted, pageable.getSort()));
return JpaManagementHelper.convertPage(rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), pageable), pageable); return JpaManagementHelper.convertPage(rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), pageable), pageable);
} }
@@ -281,7 +274,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override @Override
public Page<Rollout> findByRsqlWithDetailedStatus(final String rsql, final boolean deleted, final Pageable pageable) { public Page<Rollout> findByRsqlWithDetailedStatus(final String rsql, final boolean deleted, final Pageable pageable) {
final List<Specification<JpaRollout>> specList = List.of( final List<Specification<JpaRollout>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, RolloutFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, RolloutFields.class),
RolloutSpecification.isDeleted(deleted, pageable.getSort())); RolloutSpecification.isDeleted(deleted, pageable.getSort()));
return appendStatusDetails(JpaManagementHelper.convertPage( return appendStatusDetails(JpaManagementHelper.convertPage(
rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), JpaRollout_.GRAPH_ROLLOUT_DS, pageable), pageable)); rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), JpaRollout_.GRAPH_ROLLOUT_DS, pageable), pageable));

View File

@@ -58,7 +58,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.AuditorAware; import org.springframework.data.domain.AuditorAware;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -66,7 +65,6 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -89,8 +87,6 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
private final AuditorAware<String> auditorProvider; private final AuditorAware<String> auditorProvider;
private final ArtifactManagement artifactManagement; private final ArtifactManagement artifactManagement;
private final QuotaManagement quotaManagement; private final QuotaManagement quotaManagement;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
@SuppressWarnings("java:S107") @SuppressWarnings("java:S107")
public JpaSoftwareModuleManagement(final EntityManager entityManager, public JpaSoftwareModuleManagement(final EntityManager entityManager,
@@ -98,9 +94,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleRepository softwareModuleRepository,
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository, final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider, final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement, final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
final VirtualPropertyReplacer virtualPropertyReplacer,
final Database database) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.distributionSetRepository = distributionSetRepository; this.distributionSetRepository = distributionSetRepository;
this.softwareModuleRepository = softwareModuleRepository; this.softwareModuleRepository = softwareModuleRepository;
@@ -109,8 +103,6 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
this.auditorProvider = auditorProvider; this.auditorProvider = auditorProvider;
this.artifactManagement = artifactManagement; this.artifactManagement = artifactManagement;
this.quotaManagement = quotaManagement; this.quotaManagement = quotaManagement;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
} }
@Override @Override
@@ -261,8 +253,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
@Override @Override
public Page<SoftwareModule> findByRsql(final String rsql, final Pageable pageable) { public Page<SoftwareModule> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, List.of( return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, SoftwareModuleFields.class, virtualPropertyReplacer, RsqlUtility.getInstance().buildRsqlSpecification(rsql, SoftwareModuleFields.class),
database),
SoftwareModuleSpecification.isNotDeleted()), pageable); SoftwareModuleSpecification.isNotDeleted()), pageable);
} }

View File

@@ -31,12 +31,10 @@ import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepositor
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleTypeSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleTypeSpecification;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -51,20 +49,15 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
private final DistributionSetTypeRepository distributionSetTypeRepository; private final DistributionSetTypeRepository distributionSetTypeRepository;
private final SoftwareModuleTypeRepository softwareModuleTypeRepository; private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final SoftwareModuleRepository softwareModuleRepository; private final SoftwareModuleRepository softwareModuleRepository;
private final Database database;
public JpaSoftwareModuleTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository, public JpaSoftwareModuleTypeManagement(
final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final SoftwareModuleRepository softwareModuleRepository) {
final SoftwareModuleRepository softwareModuleRepository,
final Database database) {
this.distributionSetTypeRepository = distributionSetTypeRepository; this.distributionSetTypeRepository = distributionSetTypeRepository;
this.softwareModuleTypeRepository = softwareModuleTypeRepository; this.softwareModuleTypeRepository = softwareModuleTypeRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.softwareModuleRepository = softwareModuleRepository; this.softwareModuleRepository = softwareModuleRepository;
this.database = database;
} }
@Override @Override
@@ -144,8 +137,7 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
@Override @Override
public Page<SoftwareModuleType> findByRsql(final String rsql, final Pageable pageable) { public Page<SoftwareModuleType> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleTypeRepository, List.of( return JpaManagementHelper.findAllWithCountBySpec(softwareModuleTypeRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, SoftwareModuleTypeFields.class, RsqlUtility.getInstance().buildRsqlSpecification(rsql, SoftwareModuleTypeFields.class),
virtualPropertyReplacer, database),
SoftwareModuleTypeSpecification.isNotDeleted()), pageable SoftwareModuleTypeSpecification.isNotDeleted()), pageable
); );
} }

View File

@@ -14,7 +14,6 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import jakarta.persistence.EntityManager;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import cz.jirutka.rsql.parser.RSQLParserException; import cz.jirutka.rsql.parser.RSQLParserException;
@@ -51,7 +50,6 @@ import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
@@ -60,7 +58,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -77,7 +74,6 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
private final TargetFilterQueryRepository targetFilterQueryRepository; private final TargetFilterQueryRepository targetFilterQueryRepository;
private final TargetManagement targetManagement; private final TargetManagement targetManagement;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final DistributionSetManagement distributionSetManagement; private final DistributionSetManagement distributionSetManagement;
private final QuotaManagement quotaManagement; private final QuotaManagement quotaManagement;
private final TenantConfigurationManagement tenantConfigurationManagement; private final TenantConfigurationManagement tenantConfigurationManagement;
@@ -85,29 +81,23 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
private final SystemSecurityContext systemSecurityContext; private final SystemSecurityContext systemSecurityContext;
private final ContextAware contextAware; private final ContextAware contextAware;
private final AuditorAware<String> auditorAware; private final AuditorAware<String> auditorAware;
private final EntityManager entityManager;
private final Database database;
@SuppressWarnings("java:S107") @SuppressWarnings("java:S107")
public JpaTargetFilterQueryManagement(final TargetFilterQueryRepository targetFilterQueryRepository, public JpaTargetFilterQueryManagement(
final TargetManagement targetManagement, final VirtualPropertyReplacer virtualPropertyReplacer, final TargetFilterQueryRepository targetFilterQueryRepository,
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement, final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
final Database database, final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigurationManagement,
final RepositoryProperties repositoryProperties, final RepositoryProperties repositoryProperties,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware, final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware) {
final EntityManager entityManager) {
this.targetFilterQueryRepository = targetFilterQueryRepository; this.targetFilterQueryRepository = targetFilterQueryRepository;
this.targetManagement = targetManagement; this.targetManagement = targetManagement;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.distributionSetManagement = distributionSetManagement; this.distributionSetManagement = distributionSetManagement;
this.quotaManagement = quotaManagement; this.quotaManagement = quotaManagement;
this.database = database;
this.tenantConfigurationManagement = tenantConfigurationManagement; this.tenantConfigurationManagement = tenantConfigurationManagement;
this.repositoryProperties = repositoryProperties; this.repositoryProperties = repositoryProperties;
this.systemSecurityContext = systemSecurityContext; this.systemSecurityContext = systemSecurityContext;
this.contextAware = contextAware; this.contextAware = contextAware;
this.auditorAware = auditorAware; this.auditorAware = auditorAware;
this.entityManager = entityManager;
} }
@Override @Override
@@ -119,7 +109,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
create.getQuery().ifPresent(query -> { create.getQuery().ifPresent(query -> {
// validate the RSQL query syntax // validate the RSQL query syntax
RsqlUtility.validateRsqlFor(query, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); RsqlUtility.getInstance().validateRsqlFor(query, TargetFields.class, JpaTarget.class);
// enforce the 'max targets per auto assign' quota right here even // enforce the 'max targets per auto assign' quota right here even
// if the result of the filter query can vary over time // if the result of the filter query can vary over time
@@ -148,7 +138,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
@Override @Override
public boolean verifyTargetFilterQuerySyntax(final String query) { public boolean verifyTargetFilterQuerySyntax(final String query) {
try { try {
RsqlUtility.validateRsqlFor(query, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); RsqlUtility.getInstance().validateRsqlFor(query, TargetFields.class, JpaTarget.class);
return true; return true;
} catch (final RSQLParserException | RSQLParameterUnsupportedFieldException e) { } catch (final RSQLParserException | RSQLParameterUnsupportedFieldException e) {
log.debug("The RSQL query '{}}' is invalid.", query, e); log.debug("The RSQL query '{}}' is invalid.", query, e);
@@ -195,8 +185,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
@Override @Override
public Page<TargetFilterQuery> findByRsql(final String rsqlFilter, final Pageable pageable) { public Page<TargetFilterQuery> findByRsql(final String rsqlFilter, final Pageable pageable) {
final List<Specification<JpaTargetFilterQuery>> specList = !ObjectUtils.isEmpty(rsqlFilter) final List<Specification<JpaTargetFilterQuery>> specList = !ObjectUtils.isEmpty(rsqlFilter)
? Collections.singletonList(RsqlUtility.buildRsqlSpecification(rsqlFilter, ? Collections.singletonList(RsqlUtility.getInstance().buildRsqlSpecification(rsqlFilter, TargetFilterQueryFields.class))
TargetFilterQueryFields.class, virtualPropertyReplacer, database))
: Collections.emptyList(); : Collections.emptyList();
return JpaManagementHelper.findAllWithCountBySpec(targetFilterQueryRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(targetFilterQueryRepository, specList, pageable);
@@ -227,8 +216,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
final List<Specification<JpaTargetFilterQuery>> specList = new ArrayList<>(2); final List<Specification<JpaTargetFilterQuery>> specList = new ArrayList<>(2);
specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet)); specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet));
if (!ObjectUtils.isEmpty(rsql)) { if (!ObjectUtils.isEmpty(rsql)) {
specList.add(RsqlUtility.buildRsqlSpecification(rsql, TargetFilterQueryFields.class, specList.add(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFilterQueryFields.class));
virtualPropertyReplacer, database));
} }
return JpaManagementHelper.findAllWithCountBySpec(targetFilterQueryRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(targetFilterQueryRepository, specList, pageable);

View File

@@ -74,14 +74,12 @@ import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult; import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -104,8 +102,6 @@ public class JpaTargetManagement implements TargetManagement {
private final TargetFilterQueryRepository targetFilterQueryRepository; private final TargetFilterQueryRepository targetFilterQueryRepository;
private final TargetTagRepository targetTagRepository; private final TargetTagRepository targetTagRepository;
private final TenantAware tenantAware; private final TenantAware tenantAware;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
@SuppressWarnings("java:S107") @SuppressWarnings("java:S107")
public JpaTargetManagement(final EntityManager entityManager, public JpaTargetManagement(final EntityManager entityManager,
@@ -114,8 +110,7 @@ public class JpaTargetManagement implements TargetManagement {
final RolloutGroupRepository rolloutGroupRepository, final RolloutGroupRepository rolloutGroupRepository,
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetFilterQueryRepository targetFilterQueryRepository,
final TargetTagRepository targetTagRepository, final TargetTagRepository targetTagRepository,
final TenantAware tenantAware, final VirtualPropertyReplacer virtualPropertyReplacer, final TenantAware tenantAware) {
final Database database) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.distributionSetManagement = distributionSetManagement; this.distributionSetManagement = distributionSetManagement;
this.quotaManagement = quotaManagement; this.quotaManagement = quotaManagement;
@@ -125,8 +120,6 @@ public class JpaTargetManagement implements TargetManagement {
this.targetFilterQueryRepository = targetFilterQueryRepository; this.targetFilterQueryRepository = targetFilterQueryRepository;
this.targetTagRepository = targetTagRepository; this.targetTagRepository = targetTagRepository;
this.tenantAware = tenantAware; this.tenantAware = tenantAware;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
} }
@Override @Override
@@ -157,22 +150,20 @@ public class JpaTargetManagement implements TargetManagement {
public long countByRsql(final String rsql) { public long countByRsql(final String rsql) {
return JpaManagementHelper.countBySpec( return JpaManagementHelper.countBySpec(
targetRepository, targetRepository,
List.of(RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database))); List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class)));
} }
@Override @Override
public long countByRsqlAndUpdatable(String rsql) { public long countByRsqlAndUpdatable(String rsql) {
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database)); RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class));
return targetRepository.count( return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
AccessController.Operation.UPDATE,
combineWithAnd(specList));
} }
@Override @Override
public long countByRsqlAndCompatible(final String rsql, final Long distributionSetIdTypeId) { public long countByRsqlAndCompatible(final String rsql, final Long distributionSetIdTypeId) {
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId)); TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
return JpaManagementHelper.countBySpec(targetRepository, specList); return JpaManagementHelper.countBySpec(targetRepository, specList);
} }
@@ -180,7 +171,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override @Override
public long countByRsqlAndCompatibleAndUpdatable(String rsql, Long distributionSetIdTypeId) { public long countByRsqlAndCompatibleAndUpdatable(String rsql, Long distributionSetIdTypeId) {
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId)); TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList)); return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
} }
@@ -253,7 +244,7 @@ public class JpaTargetManagement implements TargetManagement {
.findAllWithoutCount( .findAllWithoutCount(
AccessController.Operation.UPDATE, AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId), TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))), TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))),
pageable) pageable)
@@ -268,8 +259,7 @@ public class JpaTargetManagement implements TargetManagement {
return targetRepository.count( return targetRepository.count(
AccessController.Operation.UPDATE, AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification( RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
rsql, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId), TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId)))); TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))));
} }
@@ -280,7 +270,7 @@ public class JpaTargetManagement implements TargetManagement {
return targetRepository return targetRepository
.findAllWithoutCount(AccessController.Operation.UPDATE, .findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isNotInRolloutGroups(groups), TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))), TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))),
pageable) pageable)
@@ -292,7 +282,7 @@ public class JpaTargetManagement implements TargetManagement {
final String rsql, final Collection<Long> groups, final DistributionSetType dsType) { final String rsql, final Collection<Long> groups, final DistributionSetType dsType) {
return targetRepository.count(AccessController.Operation.UPDATE, return targetRepository.count(AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isNotInRolloutGroups(groups), TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId())))); TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
} }
@@ -319,7 +309,7 @@ public class JpaTargetManagement implements TargetManagement {
return targetRepository return targetRepository
.findAllWithoutCount(AccessController.Operation.UPDATE, .findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasNoOverridingActionsAndNotInRollout(rolloutId), TargetSpecifications.hasNoOverridingActionsAndNotInRollout(rolloutId),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetType.getId()))), TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetType.getId()))),
pageable) pageable)
@@ -355,7 +345,7 @@ public class JpaTargetManagement implements TargetManagement {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId); final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId())); TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId()));
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable);
@@ -395,7 +385,7 @@ public class JpaTargetManagement implements TargetManagement {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId); final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId())); TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId()));
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable);
@@ -416,7 +406,7 @@ public class JpaTargetManagement implements TargetManagement {
public Slice<Target> findByRsql(final String rsql, final Pageable pageable) { public Slice<Target> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithoutCountBySpec( return JpaManagementHelper.findAllWithoutCountBySpec(
targetRepository, targetRepository,
List.of(RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database)), pageable List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class)), pageable
); );
} }
@@ -426,8 +416,8 @@ public class JpaTargetManagement implements TargetManagement {
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId)); .orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
return JpaManagementHelper.findAllWithoutCountBySpec( return JpaManagementHelper.findAllWithoutCountBySpec(
targetRepository, List.of(RsqlUtility.buildRsqlSpecification( targetRepository, List.of(RsqlUtility.getInstance().buildRsqlSpecification(
targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyReplacer, database)), pageable targetFilterQuery.getQuery(), TargetFields.class)), pageable
); );
} }
@@ -442,7 +432,7 @@ public class JpaTargetManagement implements TargetManagement {
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId); throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasTag(tagId)); TargetSpecifications.hasTag(tagId));
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable);
@@ -611,12 +601,12 @@ public class JpaTargetManagement implements TargetManagement {
@Override @Override
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable( public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
final String controllerId, final long distributionSetId, final String targetFilterQuery) { final String controllerId, final long distributionSetId, final String targetFilterQuery) {
RsqlUtility.validateRsqlFor(targetFilterQuery, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); RsqlUtility.getInstance().validateRsqlFor(targetFilterQuery, TargetFields.class, JpaTarget.class);
final DistributionSet ds = distributionSetManagement.get(distributionSetId) final DistributionSet ds = distributionSetManagement.get(distributionSetId)
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distributionSetId)); .orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distributionSetId));
final Long distSetTypeId = ds.getType().getId(); final Long distSetTypeId = ds.getType().getId();
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database), RsqlUtility.getInstance().buildRsqlSpecification(targetFilterQuery, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId), TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId), TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId),
TargetSpecifications.hasControllerId(controllerId)); TargetSpecifications.hasControllerId(controllerId));

View File

@@ -29,11 +29,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -48,16 +46,8 @@ public class JpaTargetTagManagement implements TargetTagManagement {
private final TargetTagRepository targetTagRepository; private final TargetTagRepository targetTagRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer; public JpaTargetTagManagement(final TargetTagRepository targetTagRepository) {
private final Database database; this.targetTagRepository = targetTagRepository;;
public JpaTargetTagManagement(
final TargetTagRepository targetTagRepository,
final VirtualPropertyReplacer virtualPropertyReplacer,
final Database database) {
this.targetTagRepository = targetTagRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
} }
@Override @Override
@@ -105,7 +95,7 @@ public class JpaTargetTagManagement implements TargetTagManagement {
@Override @Override
public Page<TargetTag> findByRsql(final String rsql, final Pageable pageable) { public Page<TargetTag> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(targetTagRepository, Collections.singletonList( return JpaManagementHelper.findAllWithCountBySpec(targetTagRepository, Collections.singletonList(
RsqlUtility.buildRsqlSpecification(rsql, TargetTagFields.class, virtualPropertyReplacer, database)), pageable); RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetTagFields.class)), pageable);
} }
@Override @Override

View File

@@ -38,12 +38,10 @@ import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -60,9 +58,6 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
private final TargetRepository targetRepository; private final TargetRepository targetRepository;
private final DistributionSetTypeRepository distributionSetTypeRepository; private final DistributionSetTypeRepository distributionSetTypeRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
private final QuotaManagement quotaManagement; private final QuotaManagement quotaManagement;
/** /**
@@ -70,18 +65,13 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
* *
* @param targetTypeRepository Target type repository * @param targetTypeRepository Target type repository
* @param targetRepository Target repository * @param targetRepository Target repository
* @param virtualPropertyReplacer replacer
* @param database database
*/ */
public JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository, public JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository,
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository, final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
final QuotaManagement quotaManagement) { final QuotaManagement quotaManagement) {
this.targetTypeRepository = targetTypeRepository; this.targetTypeRepository = targetTypeRepository;
this.targetRepository = targetRepository; this.targetRepository = targetRepository;
this.distributionSetTypeRepository = distributionSetTypeRepository; this.distributionSetTypeRepository = distributionSetTypeRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
this.quotaManagement = quotaManagement; this.quotaManagement = quotaManagement;
} }
@@ -145,10 +135,10 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
@Override @Override
public Page<TargetType> findByRsql(final String rsql, final Pageable pageable) { public Page<TargetType> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(targetTypeRepository, List.of( return JpaManagementHelper.findAllWithCountBySpec(
RsqlUtility.buildRsqlSpecification( targetTypeRepository,
rsql, TargetTypeFields.class, virtualPropertyReplacer, database)), pageable List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetTypeFields.class)),
); pageable);
} }
@Override @Override

View File

@@ -12,7 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.management;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.Assertions.fail;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
@@ -69,7 +69,7 @@ import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult; import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.test.matcher.Expect; import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch; import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
@@ -1091,7 +1091,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void findTargetsByRsqlWithTypeAndMetadata() { void findTargetsByRsqlWithTypeAndMetadata() {
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G1) { if (RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G1) {
// legacy visitor fail with that // legacy visitor fail with that
return; return;
} }

View File

@@ -11,14 +11,12 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
import jakarta.persistence.EntityManager;
import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TargetTypeFields; import org.eclipse.hawkbit.repository.TargetTypeFields;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
@@ -28,11 +26,9 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
/** /**
@@ -45,11 +41,6 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
private static final String OR = ","; private static final String OR = ",";
private static final String AND = ";"; private static final String AND = ";";
@Autowired
protected VirtualPropertyReplacer virtualPropertyReplacer;
@Autowired
protected EntityManager entityManager;
private Target target; private Target target;
private Target target2; private Target target2;
private TargetType targetType1; private TargetType targetType1;
@@ -189,7 +180,7 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null==null", 1); // "null" check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null==null", 1); // "null" check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a==null", 0); // "null" check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a==null", 0); // "null" check
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=is=value.dot", 1); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=is=value.dot", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=is=null", 5); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=is=null", 5); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=is=null", 1 + 5); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=is=null", 1 + 5); // null check
@@ -203,22 +194,22 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null!=null2", 1); // value check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null!=null2", 1); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a!=null", 0); // "null" check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a!=null", 0); // "null" check
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.dot=not=value.dot", TargetFields.ATTRIBUTE.name() + ".test.dot=not=value.dot",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null", 1); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null", 1); // null check
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.null=not=null2", TargetFields.ATTRIBUTE.name() + ".test.null=not=null2",
1 + (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check 1 + (RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=not=null", 0); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=not=null", 0); // null check
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.dot=ne=value.dot", TargetFields.ATTRIBUTE.name() + ".test.dot=ne=value.dot",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null", 1); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null", 1); // null check
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.null=ne=null2", TargetFields.ATTRIBUTE.name() + ".test.null=ne=null2",
1 + (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check 1 + (RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=ne=null", 0); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=ne=null", 0); // null check
} }
@@ -315,7 +306,7 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist==metaValue", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".notExist==metaValue", 0);
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=metaValue", 1); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=null", 4); // null check (1 of the initial five has) assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=null", 4); // null check (1 of the initial five has)
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=*v*", 2); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=*v*", 2);
@@ -333,27 +324,27 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2);
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=not=metaValue", TargetFields.METADATA.name() + ".metaKey=not=metaValue",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=null", 2); // null check (2 of the initial five) assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=null", 2); // null check (2 of the initial five)
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".notExist=not=metaValue", TargetFields.METADATA.name() + ".notExist=not=metaValue",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=not=notExist", TargetFields.METADATA.name() + ".metaKey=not=notExist",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=ne=metaValue", TargetFields.METADATA.name() + ".metaKey=ne=metaValue",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=null", 2); // null check (2 of the initial five) assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=null", 2); // null check (2 of the initial five)
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".notExist=ne=metaValue", TargetFields.METADATA.name() + ".notExist=ne=metaValue",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=ne=notExist", TargetFields.METADATA.name() + ".metaKey=ne=notExist",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2); RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
} }
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
@@ -386,28 +377,26 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void rsqlValidTargetFields() { void rsqlValidTargetFields() {
RsqlUtility.validateRsqlFor( RsqlUtility.getInstance().validateRsqlFor(
"ID == '0123' and NAME == abcd and DESCRIPTION == absd and CREATEDAT =lt= 0123 and LASTMODIFIEDAT =gt= 0123" + "ID == '0123' and NAME == abcd and DESCRIPTION == absd and CREATEDAT =lt= 0123 and LASTMODIFIEDAT =gt= 0123" +
" and CONTROLLERID == 0123 and UPDATESTATUS == PENDING and IPADDRESS == 0123 and LASTCONTROLLERREQUESTAT == 0123" + " and CONTROLLERID == 0123 and UPDATESTATUS == PENDING and IPADDRESS == 0123 and LASTCONTROLLERREQUESTAT == 0123" +
" and tag == beta", " and tag == beta",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); TargetFields.class, JpaTarget.class);
RsqlUtility.validateRsqlFor( RsqlUtility.getInstance().validateRsqlFor(
"ASSIGNEDDS.name == abcd and ASSIGNEDDS.version == 0123 and INSTALLEDDS.name == abcd and INSTALLEDDS.version == 0123", "ASSIGNEDDS.name == abcd and ASSIGNEDDS.version == 0123 and INSTALLEDDS.name == abcd and INSTALLEDDS.version == 0123",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); TargetFields.class, JpaTarget.class);
RsqlUtility.validateRsqlFor( RsqlUtility.getInstance().validateRsqlFor(
"ATTRIBUTE.subkey1 == test and ATTRIBUTE.subkey2 == test and METADATA.metakey1 == abcd and METADATA.metavalue2 == asdfg", "ATTRIBUTE.subkey1 == test and ATTRIBUTE.subkey2 == test and METADATA.metakey1 == abcd and METADATA.metavalue2 == asdfg",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); TargetFields.class, JpaTarget.class);
RsqlUtility.validateRsqlFor( RsqlUtility.getInstance().validateRsqlFor(
"CREATEDAT =lt= ${NOW_TS} and LASTMODIFIEDAT =ge= ${OVERDUE_TS}", "CREATEDAT =lt= ${NOW_TS} and LASTMODIFIEDAT =ge= ${OVERDUE_TS}",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); TargetFields.class, JpaTarget.class);
RsqlUtility.validateRsqlFor( RsqlUtility.getInstance().validateRsqlFor(
"ATTRIBUTE.test.dot == test and ATTRIBUTE.subkey2 == test and METADATA.test.dot == abcd and METADATA.metavalue2 == asdfg", "ATTRIBUTE.test.dot == test and ATTRIBUTE.subkey2 == test and METADATA.test.dot == abcd and METADATA.metavalue2 == asdfg",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager); TargetFields.class, JpaTarget.class);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class) assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> RsqlUtility.validateRsqlFor( .isThrownBy(() -> RsqlUtility.getInstance().validateRsqlFor("wrongfield == abcd", TargetFields.class, JpaTarget.class));
"wrongfield == abcd",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager));
} }
/** /**
@@ -452,7 +441,6 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
private void assertRSQLQueryThrowsException(final String rsql) { private void assertRSQLQueryThrowsException(final String rsql) {
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class) assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> RsqlUtility.validateRsqlFor( .isThrownBy(() -> RsqlUtility.getInstance().validateRsqlFor(rsql, TargetFields.class, JpaTarget.class));
rsql, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager));
} }
} }

View File

@@ -9,9 +9,9 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql; package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.G3; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.G3;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;

View File

@@ -1,497 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.Type;
import org.eclipse.hawkbit.repository.DistributionSetFields;
import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
/**
* Feature: Component Tests - Repository<br/>
* Story: RSQL search utility
*/
@Disabled
// TODO: fully document tests -> description for long text and reasonable
// method name as short text
class RsqlUtilityTest {
private static final TenantConfigurationValue<String> TEST_POLLING_TIME_INTERVAL =
TenantConfigurationValue.<String> builder().value("00:05:00").build();
private static final TenantConfigurationValue<String> TEST_POLLING_OVERDUE_TIME_INTERVAL =
TenantConfigurationValue.<String> builder().value("00:07:37").build();
@Spy
private final VirtualPropertyResolver macroResolver = new VirtualPropertyResolver();
private final Database testDb = Database.H2;
@MockitoBean
private TenantConfigurationManagement confMgmt;
@MockitoBean
private SystemSecurityContext securityContext;
@Mock
private Root<Object> baseSoftwareModuleRootMock;
@Mock
private CriteriaQuery<SoftwareModule> criteriaQueryMock;
@Mock
private CriteriaBuilder criteriaBuilderMock;
@Mock
private Subquery<SoftwareModule> subqueryMock;
@Mock
private Root<SoftwareModule> subqueryRootMock;
@Mock
private Attribute attribute;
@BeforeEach
void beforeEach() {
setupRoot(baseSoftwareModuleRootMock);
setupRoot(subqueryRootMock);
}
@Test
void wrongFieldThrowUnsupportedFieldException() {
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
final Specification<Object> rsqlSpecification = RsqlUtility.buildRsqlSpecification("unknownField==abc", SoftwareModuleFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterUnsupportedFieldException because of unknown RSQL field")
.isThrownBy(() -> rsqlSpecification.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
}
@Test
void wrongRsqlMapSyntaxThrowSyntaxException() {
final Specification<Object> rsqlSpecification =
RsqlUtility.buildRsqlSpecification(TargetFields.ATTRIBUTE + "==abc", TargetFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterSyntaxException for target attributes map, caused by wrong RSQL syntax (key was not present)")
.isThrownBy(() -> rsqlSpecification.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
final Specification<Object> rsqlSpecification2 =
RsqlUtility.buildRsqlSpecification(TargetFields.ATTRIBUTE + ".unknown.wrong==abc", TargetFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterSyntaxException for target attributes map, caused by wrong RSQL syntax (key includes dots)")
.isThrownBy(() -> rsqlSpecification2.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
final Specification<Object> rsqlSpecification3 =
RsqlUtility.buildRsqlSpecification(TargetFields.METADATA + ".unknown.wrong==abc", TargetFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterSyntaxException for target metadata map, caused by wrong RSQL syntax (key includes dots)")
.isThrownBy(() -> rsqlSpecification3.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
final Specification<Object> rsqlSpecification4 =
RsqlUtility.buildRsqlSpecification(DistributionSetFields.METADATA + "==abc", TargetFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterSyntaxException for distribution set metadata map, caused by wrong RSQL syntax (key was not present)\"")
.isThrownBy(() -> rsqlSpecification4.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
}
@Test
void wrongRsqlSubEntitySyntaxThrowSyntaxException() {
final Specification<Object> rsqlSpecification =
RsqlUtility.buildRsqlSpecification(TargetFields.ASSIGNEDDS + "==abc", TargetFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterSyntaxException because of wrong RSQL syntax")
.isThrownBy(() -> rsqlSpecification.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
final Specification<Object> rsqlSpecification2 =
RsqlUtility.buildRsqlSpecification(TargetFields.ASSIGNEDDS + ".unknownField==abc", TargetFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterSyntaxException because of wrong RSQL syntax")
.isThrownBy(() -> rsqlSpecification2.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
final Specification<Object> rsqlSpecification3 =
RsqlUtility.buildRsqlSpecification(TargetFields.ASSIGNEDDS + ".unknownField.ToMuch==abc", TargetFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterSyntaxException because of wrong RSQL syntax")
.isThrownBy(() -> rsqlSpecification3.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
}
@Test
<T> void correctRsqlBuildsPredicate() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name==abc;version==1.2";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.get("version")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
when(criteriaBuilderMock.upper(pathOfString(baseSoftwareModuleRootMock))).thenReturn(pathOfString(baseSoftwareModuleRootMock));
when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.equal(any(Expression.class), any(String.class))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.and(any(Predicate[].class))).thenReturn(mock(Predicate.class));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
}
@Test
void correctRsqlBuildsSimpleNotEqualPredicate() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name!=abc";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
when(criteriaBuilderMock.isNull(any(Expression.class))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.notEqual(any(Expression.class), anyString())).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.upper(pathOfString(baseSoftwareModuleRootMock))).thenReturn(pathOfString(baseSoftwareModuleRootMock));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).or(any(Predicate.class), any(Predicate.class));
verify(criteriaBuilderMock, times(1)).isNull(pathOfString(baseSoftwareModuleRootMock));
verify(criteriaBuilderMock, times(1)).notEqual(pathOfString(baseSoftwareModuleRootMock), "abc".toUpperCase());
}
@Test
void correctRsqlBuildsSimpleNotLikePredicate() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name!=abc*";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
when(criteriaBuilderMock.isNull(any(Expression.class))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.notLike(any(Expression.class), anyString(), eq('\\')))
.thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.upper(pathOfString(baseSoftwareModuleRootMock))).thenReturn(pathOfString(baseSoftwareModuleRootMock));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).or(any(Predicate.class), any(Predicate.class));
verify(criteriaBuilderMock, times(1)).isNull(pathOfString(baseSoftwareModuleRootMock));
verify(criteriaBuilderMock, times(1)).notLike(pathOfString(baseSoftwareModuleRootMock), "abc%".toUpperCase(), '\\');
}
@Test
void correctRsqlBuildsNotSimpleNotLikePredicate() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// with this query a subquery has to be made, so it is no simple query
final String correctRsql = "type!=abc";
when(baseSoftwareModuleRootMock.get(anyString())).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
final Path pathMock = mock(Path.class);
when(pathMock.get(anyString())).thenReturn(pathMock);
when(subqueryRootMock.get(anyString())).thenReturn(pathMock);
when(criteriaBuilderMock.and(any(), any())).thenReturn(mock(Predicate.class));
when(criteriaQueryMock.subquery(SoftwareModule.class)).thenReturn(subqueryMock);
when(subqueryMock.from(SoftwareModule.class)).thenReturn(subqueryRootMock);
when(subqueryMock.select(subqueryRootMock)).thenReturn(subqueryMock);
when(subqueryMock.where(any(Expression.class))).thenReturn(subqueryMock);
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).not(criteriaBuilderMock.exists(eq(subqueryMock)));
}
@Test
void correctRsqlBuildsEqualPredicateWithPercentage() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name==a%";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
when(criteriaBuilderMock.equal(any(Expression.class), anyString())).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.upper(pathOfString(baseSoftwareModuleRootMock))).thenReturn(pathOfString(baseSoftwareModuleRootMock));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, Database.H2)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
verify(criteriaBuilderMock, times(1)).equal(pathOfString(baseSoftwareModuleRootMock), "a%".toUpperCase());
}
@Test
void correctRsqlBuildsLikePredicateWithPercentage() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name==a%*";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.upper(pathOfString(baseSoftwareModuleRootMock))).thenReturn(pathOfString(baseSoftwareModuleRootMock));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, Database.H2)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
verify(criteriaBuilderMock, times(1)).like(pathOfString(baseSoftwareModuleRootMock), "a\\%%".toUpperCase(), '\\');
}
// MsSQL is not officially supported
// thought it may be available through configuration and adding necessarily dependencies
// so we keep RSQL compatibility testing
@Test
void correctRsqlBuildsLikePredicateWithPercentageSQLServer() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name==a%*";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
when(criteriaBuilderMock.upper(pathOfString(baseSoftwareModuleRootMock))).thenReturn(pathOfString(baseSoftwareModuleRootMock));
when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class))).thenReturn(mock(Predicate.class));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, Database.SQL_SERVER)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
verify(criteriaBuilderMock, times(1)).like(pathOfString(baseSoftwareModuleRootMock), "a[%]%".toUpperCase(), '\\');
}
@Test
void correctRsqlBuildsLessThanPredicate() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name=lt=abc";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
when(criteriaBuilderMock.lessThan(any(Expression.class), anyString())).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class)))
.thenReturn(mock(Predicate.class));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, SoftwareModuleFields.class, null, testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
verify(criteriaBuilderMock, times(1)).lessThan(pathOfString(baseSoftwareModuleRootMock), "abc");
}
@Test
void correctRsqlWithEnumValue() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "testfield==bumlux";
when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) TestValueEnum.class);
when(criteriaBuilderMock.equal(any(Root.class), any(TestValueEnum.class))).thenReturn(mock(Predicate.class));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, TestFieldEnum.class, null, testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
verify(criteriaBuilderMock, times(1)).equal(baseSoftwareModuleRootMock, TestValueEnum.BUMLUX);
}
@Test
void wrongRsqlWithWrongEnumValue() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "testfield==unknownValue";
when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) TestValueEnum.class);
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
final Specification<Object> rsqlSpecification = RsqlUtility.buildRsqlSpecification(correctRsql, TestFieldEnum.class, null, testDb);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.as("RSQLParameterUnsupportedFieldException for wrong enum value")
.isThrownBy(() -> rsqlSpecification.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
}
/**
* Tests the resolution of overdue_ts placeholder in context of a RSQL expression.
*/
@Test
void correctRsqlWithOverdueMacro() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String overdueProp = "overdue_ts";
final String overduePropPlaceholder = "${" + overdueProp + "}";
final String correctRsql = "testfield=le=" + overduePropPlaceholder;
when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
when(criteriaBuilderMock.upper(pathOfString(baseSoftwareModuleRootMock))).thenReturn(pathOfString(baseSoftwareModuleRootMock));
when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))).thenReturn(mock(Predicate.class));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, TestFieldEnum.class, setupMacroLookup(), testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
// the macro is already replaced when passed to #lessThanOrEqualTo -> the method is never invoked with the placeholder:
verify(criteriaBuilderMock, never()).lessThanOrEqualTo(pathOfString(baseSoftwareModuleRootMock), overduePropPlaceholder);
}
/**
* Tests RSQL expression with an unknown placeholder.
*/
@Test
void correctRsqlWithUnknownMacro() {
reset0(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String overdueProp = "unknown";
final String overduePropPlaceholder = "${" + overdueProp + "}";
final String correctRsql = "testfield=le=" + overduePropPlaceholder;
when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class);
when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.<String> lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder)))
.thenReturn(mock(Predicate.class));
// test
RsqlUtility.buildRsqlSpecification(correctRsql, TestFieldEnum.class, setupMacroLookup(), testDb)
.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// verification
// the macro is unknown and hence never replaced -> #lessThanOrEqualTo is invoked with the placeholder:
verify(criteriaBuilderMock).lessThanOrEqualTo(pathOfString(baseSoftwareModuleRootMock), overduePropPlaceholder);
}
VirtualPropertyReplacer setupMacroLookup() {
when(securityContext.runAsSystem(Mockito.any())).thenAnswer(a -> ((Callable<?>) a.getArgument(0)).call());
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME, String.class))
.thenReturn(TEST_POLLING_TIME_INTERVAL);
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME, String.class))
.thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL);
return macroResolver;
}
@SuppressWarnings("unchecked")
private <Y> Path<Y> pathOfString(final Path<?> path) {
return (Path<Y>) path;
}
private void reset0(final Object... mocks) {
reset(mocks);
if (Arrays.asList(mocks).contains(baseSoftwareModuleRootMock)) {
setupRoot(baseSoftwareModuleRootMock);
}
if (Arrays.asList(mocks).contains(subqueryRootMock)) {
setupRoot(subqueryRootMock);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void setupRoot(final Root<?> root) {
final Type type = Mockito.mock(Type.class);
when(type.getPersistenceType()).thenReturn(Type.PersistenceType.BASIC);
final SingularAttribute singularAttribute = Mockito.mock(SingularAttribute.class);
when(singularAttribute.getType()).thenReturn(type);
final EntityType entityType = Mockito.mock(EntityType.class);
when(entityType.getAttribute(any())).thenReturn(singularAttribute);
when(entityType.getPersistenceType()).thenReturn(Type.PersistenceType.BASIC);
when(root.getModel()).thenReturn(entityType);
}
private enum TestFieldEnum implements RsqlQueryField {
TESTFIELD("testfield"), TESTFIELD_WITH_SUB_ENTITIES("testfieldWithSubEntities", "subentity11", "subentity22");
private final String fieldName;
private final List<String> subEntityAttributes;
TestFieldEnum(final String fieldName) {
this(fieldName, new String[0]);
}
TestFieldEnum(final String fieldName, final String... subEntityAttributes) {
this.fieldName = fieldName;
this.subEntityAttributes = (Arrays.asList(subEntityAttributes));
}
@Override
public String getJpaEntityFieldName() {
return this.fieldName;
}
@Override
public List<String> getSubEntityAttributes() {
return subEntityAttributes;
}
}
private enum TestValueEnum {
BUMLUX;
}
@Configuration
static class Config {
@Bean
TenantConfigurationManagementHolder tenantConfigurationManagementHolder() {
return TenantConfigurationManagementHolder.getInstance();
}
@Bean
SystemSecurityContextHolder systemSecurityContextHolder() {
return SystemSecurityContextHolder.getInstance();
}
@Bean
RsqlConfigHolder rsqlConfigHolder() {
return RsqlConfigHolder.getInstance();
}
}
}