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.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder;
import org.springframework.orm.jpa.vendor.Database;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder;
public class HawkbitQlToSql {
private static final Database DATABASE = Database.H2;
private final EntityManager entityManager;
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 CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final RsqlToSpecBuilder defaultRsqlToSpecBuilder = RsqlConfigHolder.getInstance().getRsqlToSpecBuilder();
final RsqlToSpecBuilder defaultRsqlToSpecBuilder = RsqlUtility.getInstance().getRsqlToSpecBuilder();
if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) {
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder);
RsqlUtility.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder);
}
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));
} finally {
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;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.G3;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import cz.jirutka.rsql.parser.RSQLParserException;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.text.StrLookup;
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.rsql.VirtualPropertyReplacer;
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.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.
*/
@Slf4j
@Getter
@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
@@ -73,25 +134,16 @@ public final class RsqlUtility {
*
* @param rsql the rsql query to be parsed
* @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
* @throws RSQLParameterUnsupportedFieldException if a field in the RSQL string is used but not provided by the
* given {@code fieldNameProvider}
* @throws RSQLParameterSyntaxException if the RSQL syntax is wrong
*/
public static <A extends Enum<A> & RsqlQueryField, T> Specification<T> buildRsqlSpecification(
final String rsql, final Class<A> rsqlQueryFieldType,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == G3) {
return new SpecificationBuilder<T>(
virtualPropertyReplacer,
!RsqlConfigHolder.getInstance().isCaseInsensitiveDB() && RsqlConfigHolder.getInstance().isIgnoreCase(),
database)
.specification(RsqlParser.parse(
RsqlConfigHolder.getInstance().isCaseInsensitiveDB() || RsqlConfigHolder.getInstance().isIgnoreCase()
? rsql.toLowerCase() : rsql,
rsqlQueryFieldType));
public <A extends Enum<A> & RsqlQueryField, T> Specification<T> buildRsqlSpecification(
final String rsql, final Class<A> rsqlQueryFieldType) {
if (rsqlToSpecBuilder == RsqlToSpecBuilder.G3) {
return new SpecificationBuilder<T>(virtualPropertyReplacer, !caseInsensitiveDB && ignoreCase, database)
.specification(RsqlParser.parse(caseInsensitiveDB || ignoreCase ? rsql.toLowerCase() : rsql, rsqlQueryFieldType));
} else {
return new SpecificationBuilderLegacy<A, T>(rsqlQueryFieldType, virtualPropertyReplacer, database).specification(rsql);
}
@@ -101,18 +153,16 @@ public final class RsqlUtility {
* Validates the RSQL string
*
* @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 RSQLParameterUnsupportedFieldException if RSQL key is not allowed
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <A extends Enum<A> & RsqlQueryField> void validateRsqlFor(
final String rsql, final Class<A> rsqlQueryFieldType,
final Class<?> jpaType,
final VirtualPropertyReplacer virtualPropertyReplacer, final EntityManager entityManager) {
public <A extends Enum<A> & RsqlQueryField> void validateRsqlFor(
final String rsql, final Class<A> rsqlQueryFieldType, final Class<?> jpaType) {
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<?> criteriaQuery = criteriaBuilder.createQuery(jpaType);
buildRsqlSpecification(rsql, rsqlQueryFieldType, virtualPropertyReplacer, null)
.toPredicate(criteriaQuery.from((Class) jpaType), criteriaQuery, criteriaBuilder);
buildRsqlSpecification(rsql, rsqlQueryFieldType).toPredicate(criteriaQuery.from((Class) jpaType), criteriaQuery, criteriaBuilder);
}
}

View File

@@ -10,7 +10,7 @@
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.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import java.util.List;
@@ -24,7 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
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.springframework.data.jpa.domain.Specification;
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) {
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);
final boolean ensureIgnoreCase = !rsqlConfigHolder.isCaseInsensitiveDB() && rsqlConfigHolder.isIgnoreCase();
final boolean ensureIgnoreCase = !rsqlUtility.isCaseInsensitiveDB() && rsqlUtility.isIgnoreCase();
final RSQLVisitor<List<Predicate>, String> jpqQueryRSQLVisitor =
rsqlConfigHolder.getRsqlToSpecBuilder() == LEGACY_G1
rsqlUtility.getRsqlToSpecBuilder() == LEGACY_G1
? new JpaQueryRsqlVisitor<>(root, cb, rsqlQueryFieldType, virtualPropertyReplacer, database, query, ensureIgnoreCase)
: new JpaQueryRsqlVisitorG2<>(rsqlQueryFieldType, root, query, cb, database, virtualPropertyReplacer, ensureIgnoreCase);
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);
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) {
throw new RSQLParameterSyntaxException("RSQL filter must not be null", e);
} catch (final RSQLParserException e) {

View File

@@ -7,7 +7,7 @@
*
* 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.Set;

View File

@@ -7,7 +7,7 @@
*
* 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.repository.CrudRepository;

View File

@@ -7,10 +7,10 @@
*
* 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.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G2;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2;
import java.util.Arrays;
import java.util.List;
@@ -18,9 +18,9 @@ import java.util.List;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
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.RsqlConfigHolder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.data.jpa.domain.Specification;
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 static void runWithRsqlToSpecBuilder(final Runnable runnable, final RsqlToSpecBuilder rsqlToSpecBuilder) {
final RsqlToSpecBuilder defaultBuilder = RsqlConfigHolder.getInstance().getRsqlToSpecBuilder();
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder);
final RsqlToSpecBuilder defaultBuilder = RsqlUtility.getInstance().getRsqlToSpecBuilder();
RsqlUtility.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder);
try {
runnable.run();
} finally {
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(defaultBuilder);
RsqlUtility.getInstance().setRsqlToSpecBuilder(defaultBuilder);
}
}

View File

@@ -7,12 +7,12 @@
*
* 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.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.RsqlToSpecBuilder.G3;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.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.G3;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2;
import java.util.List;
import java.util.Map;
@@ -22,11 +22,9 @@ import java.util.stream.StreamSupport;
import jakarta.persistence.EntityManager;
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.rsql.RsqlParser;
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.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
@@ -491,8 +489,8 @@ class SpecificationBuilderTest {
return builder.specification(RsqlParser.parse(rsql));
}
private static RsqlConfigHolder.RsqlToSpecBuilder getRsqlToSpecBuilder() {
return RsqlConfigHolder.getInstance().getRsqlToSpecBuilder();
private static RsqlUtility.RsqlToSpecBuilder getRsqlToSpecBuilder() {
return RsqlUtility.getInstance().getRsqlToSpecBuilder();
}
@SpringBootConfiguration

View File

@@ -7,16 +7,13 @@
*
* 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.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -7,7 +7,7 @@
*
* 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.repository.CrudRepository;

View File

@@ -7,7 +7,7 @@
*
* 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.GeneratedValue;

View File

@@ -7,7 +7,7 @@
*
* 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.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.helper.SystemSecurityContextHolder;
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.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
@@ -538,15 +538,13 @@ public class RepositoryApplicationConfiguration {
final TargetRepository targetRepository,
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement tenantConfigurationManagement,
final VirtualPropertyReplacer virtualPropertyReplacer, final SoftwareModuleRepository softwareModuleRepository,
final DistributionSetTagRepository distributionSetTagRepository,
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
final SoftwareModuleRepository softwareModuleRepository,
final DistributionSetTagRepository distributionSetTagRepository, final RepositoryProperties repositoryProperties) {
return new JpaDistributionSetManagement(entityManager, distributionSetRepository, distributionSetTagManagement,
systemManagement, distributionSetTypeManagement, quotaManagement,
targetRepository, targetFilterQueryRepository, actionRepository,
TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement),
virtualPropertyReplacer, softwareModuleRepository, distributionSetTagRepository,
properties.getDatabase(), repositoryProperties);
softwareModuleRepository, distributionSetTagRepository, repositoryProperties);
}
/**
@@ -560,11 +558,9 @@ public class RepositoryApplicationConfiguration {
final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
final QuotaManagement quotaManagement) {
return new JpaDistributionSetTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
distributionSetRepository, targetTypeRepository, virtualPropertyReplacer, properties.getDatabase(),
quotaManagement);
distributionSetRepository, targetTypeRepository, quotaManagement);
}
/**
@@ -576,10 +572,8 @@ public class RepositoryApplicationConfiguration {
@ConditionalOnMissingBean
TargetTypeManagement targetTypeManagement(final TargetTypeRepository targetTypeRepository,
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
final QuotaManagement quotaManagement) {
return new JpaTargetTypeManagement(targetTypeRepository, targetRepository, distributionSetTypeRepository,
virtualPropertyReplacer, properties.getDatabase(), quotaManagement);
return new JpaTargetTypeManagement(targetTypeRepository, targetRepository, distributionSetTypeRepository, quotaManagement);
}
/**
@@ -618,18 +612,16 @@ public class RepositoryApplicationConfiguration {
*/
@Bean
@ConditionalOnMissingBean
TargetManagement targetManagement(final EntityManager entityManager, final QuotaManagement quotaManagement,
TargetManagement targetManagement(
final EntityManager entityManager, final QuotaManagement quotaManagement,
final TargetRepository targetRepository,
final RolloutGroupRepository rolloutGroupRepository,
final TargetFilterQueryRepository targetFilterQueryRepository,
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
final TenantAware tenantAware,
final VirtualPropertyReplacer virtualPropertyReplacer,
final JpaProperties properties, final DistributionSetManagement distributionSetManagement) {
final TenantAware tenantAware, final DistributionSetManagement distributionSetManagement) {
return new JpaTargetManagement(entityManager, distributionSetManagement, quotaManagement, targetRepository,
targetTypeRepository, rolloutGroupRepository, targetFilterQueryRepository,
targetTagRepository, tenantAware, virtualPropertyReplacer,
properties.getDatabase());
targetTagRepository, tenantAware);
}
/**
@@ -637,25 +629,20 @@ public class RepositoryApplicationConfiguration {
*
* @param targetFilterQueryRepository holding {@link TargetFilterQuery} entities
* @param targetManagement managing {@link Target} entities
* @param virtualPropertyReplacer for RSQL handling
* @param distributionSetManagement for auto assign DS access
* @param quotaManagement to access quotas
* @param properties JPA properties
* @return a new {@link TargetFilterQueryManagement}
*/
@Bean
@ConditionalOnMissingBean
TargetFilterQueryManagement targetFilterQueryManagement(
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetManagement targetManagement,
final VirtualPropertyReplacer virtualPropertyReplacer,
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
final JpaProperties properties, final TenantConfigurationManagement tenantConfigurationManagement,
final RepositoryProperties repositoryProperties,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware,
final EntityManager entityManager) {
final TenantConfigurationManagement tenantConfigurationManagement, final RepositoryProperties repositoryProperties,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware) {
return new JpaTargetFilterQueryManagement(targetFilterQueryRepository, targetManagement,
virtualPropertyReplacer, distributionSetManagement, quotaManagement, properties.getDatabase(),
tenantConfigurationManagement, repositoryProperties, systemSecurityContext, contextAware, auditorAware, entityManager);
distributionSetManagement, quotaManagement, tenantConfigurationManagement, repositoryProperties,
systemSecurityContext, contextAware, auditorAware);
}
/**
@@ -665,11 +652,8 @@ public class RepositoryApplicationConfiguration {
*/
@Bean
@ConditionalOnMissingBean
TargetTagManagement targetTagManagement(final TargetTagRepository targetTagRepository,
final VirtualPropertyReplacer virtualPropertyReplacer,
final JpaProperties properties) {
return new JpaTargetTagManagement(targetTagRepository, virtualPropertyReplacer,
properties.getDatabase());
TargetTagManagement targetTagManagement(final TargetTagRepository targetTagRepository) {
return new JpaTargetTagManagement(targetTagRepository);
}
/**
@@ -681,10 +665,9 @@ public class RepositoryApplicationConfiguration {
@ConditionalOnMissingBean
DistributionSetTagManagement distributionSetTagManagement(
final DistributionSetTagRepository distributionSetTagRepository,
final DistributionSetRepository distributionSetRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
final DistributionSetRepository distributionSetRepository) {
return new JpaDistributionSetTagManagement(
distributionSetTagRepository, distributionSetRepository, virtualPropertyReplacer, properties.getDatabase());
distributionSetTagRepository, distributionSetRepository);
}
/**
@@ -699,13 +682,9 @@ public class RepositoryApplicationConfiguration {
final SoftwareModuleRepository softwareModuleRepository,
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement,
final VirtualPropertyReplacer virtualPropertyReplacer,
final JpaProperties properties) {
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
return new JpaSoftwareModuleManagement(entityManager, distributionSetRepository, softwareModuleRepository,
softwareModuleMetadataRepository, softwareModuleTypeRepository, auditorProvider, artifactManagement,
quotaManagement, virtualPropertyReplacer,
properties.getDatabase());
softwareModuleMetadataRepository, softwareModuleTypeRepository, auditorProvider, artifactManagement, quotaManagement);
}
/**
@@ -718,11 +697,8 @@ public class RepositoryApplicationConfiguration {
SoftwareModuleTypeManagement softwareModuleTypeManagement(
final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer,
final SoftwareModuleRepository softwareModuleRepository,
final JpaProperties properties) {
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
virtualPropertyReplacer, softwareModuleRepository, properties.getDatabase());
final SoftwareModuleRepository softwareModuleRepository) {
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository, softwareModuleRepository);
}
@Bean
@@ -765,14 +741,12 @@ public class RepositoryApplicationConfiguration {
final TenantConfigurationManagement tenantConfigurationManagement,
final QuotaManagement quotaManagement,
final AfterTransactionCommitExecutor afterCommit,
final VirtualPropertyReplacer virtualPropertyReplacer,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final JpaProperties properties,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware,
final RepositoryProperties repositoryProperties) {
return new JpaRolloutManagement(rolloutRepository, rolloutGroupRepository, rolloutApprovalStrategy,
startNextRolloutGroupAction, rolloutStatusCache, actionRepository, targetManagement,
distributionSetManagement, tenantConfigurationManagement, quotaManagement, afterCommit,
virtualPropertyReplacer, systemSecurityContext, contextAware, properties.getDatabase(),
repositoryProperties);
systemSecurityContext, contextAware, repositoryProperties);
}
/**
@@ -798,11 +772,9 @@ public class RepositoryApplicationConfiguration {
@ConditionalOnMissingBean
RolloutGroupManagement rolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
final TargetRepository targetRepository, final EntityManager entityManager,
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
final JpaProperties properties) {
final TargetRepository targetRepository, final EntityManager entityManager, final RolloutStatusCache rolloutStatusCache) {
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 DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
final AfterTransactionCommitExecutor afterCommit,
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
final AfterTransactionCommitExecutor afterCommit, final PlatformTransactionManager txManager,
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement, targetRepository, actionStatusRepository,
auditorProvider,
afterCommit, virtualPropertyReplacer, txManager, tenantConfigurationManagement,
afterCommit, txManager, tenantConfigurationManagement,
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
RsqlConfigHolder rsqlConfigHolder() {
return RsqlConfigHolder.getInstance();
RsqlUtility rsqlUtility() {
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.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
@@ -150,7 +149,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
private final DistributionSetManagement distributionSetManagement;
private final TargetRepository targetRepository;
private final AuditorAware<String> auditorProvider;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final PlatformTransactionManager txManager;
private final OnlineDsAssignmentStrategy onlineDsAssignmentStrategy;
private final OfflineDsAssignmentStrategy offlineDsAssignmentStrategy;
@@ -166,8 +164,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
final EntityManager entityManager, final ActionRepository actionRepository,
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
final AfterTransactionCommitExecutor afterCommit,
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
final AfterTransactionCommitExecutor afterCommit, final PlatformTransactionManager txManager,
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
final Database database, final RepositoryProperties repositoryProperties) {
@@ -176,7 +173,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
this.distributionSetManagement = distributionSetManagement;
this.targetRepository = targetRepository;
this.auditorProvider = auditorProvider;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.txManager = txManager;
onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, afterCommit,
actionRepository, actionStatusRepository, quotaManagement, this::isMultiAssignmentsEnabled,
@@ -274,7 +270,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
assertTargetReadAllowed(controllerId);
final List<Specification<JpaAction>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class),
ActionSpecifications.byTargetControllerId(controllerId));
return JpaManagementHelper.countBySpec(actionRepository, specList);
@@ -287,8 +283,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override
public long countActions(final String rsql) {
final List<Specification<JpaAction>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database));
final List<Specification<JpaAction>> specList = List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class));
return JpaManagementHelper.countBySpec(actionRepository, specList);
}
@@ -312,8 +307,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override
public Slice<Action> findActions(final String rsql, final Pageable pageable) {
final List<Specification<JpaAction>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database));
final List<Specification<JpaAction>> specList = List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class));
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, specList, pageable);
}
@@ -322,7 +316,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
assertTargetReadAllowed(controllerId);
final List<Specification<JpaAction>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, ActionFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class),
ActionSpecifications.byTargetControllerId(controllerId));
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.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Statistic;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
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.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -105,10 +103,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
private final TargetFilterQueryRepository targetFilterQueryRepository;
private final ActionRepository actionRepository;
private final TenantConfigHelper tenantConfigHelper;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final SoftwareModuleRepository softwareModuleRepository;
private final DistributionSetTagRepository distributionSetTagRepository;
private final Database database;
private final RepositoryProperties repositoryProperties;
@SuppressWarnings("java:S107")
@@ -120,10 +116,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
final TargetRepository targetRepository,
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
final TenantConfigHelper tenantConfigHelper,
final VirtualPropertyReplacer virtualPropertyReplacer,
final SoftwareModuleRepository softwareModuleRepository,
final DistributionSetTagRepository distributionSetTagRepository,
final Database database,
final RepositoryProperties repositoryProperties) {
this.entityManager = entityManager;
this.distributionSetRepository = distributionSetRepository;
@@ -135,10 +129,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
this.targetFilterQueryRepository = targetFilterQueryRepository;
this.actionRepository = actionRepository;
this.tenantConfigHelper = tenantConfigHelper;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.softwareModuleRepository = softwareModuleRepository;
this.distributionSetTagRepository = distributionSetTagRepository;
this.database = database;
this.repositoryProperties = repositoryProperties;
}
@@ -282,7 +274,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override
public Page<DistributionSet> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, DistributionSetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class),
DistributionSetSpecification.isNotDeleted()), pageable);
}
@@ -551,8 +543,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
assertDsTagExists(tagId);
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, DistributionSetFields.class, virtualPropertyReplacer,
database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class),
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.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
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.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -54,17 +52,12 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
private final DistributionSetTagRepository distributionSetTagRepository;
private final DistributionSetRepository distributionSetRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
public JpaDistributionSetTagManagement(
final DistributionSetTagRepository distributionSetTagRepository,
final DistributionSetRepository distributionSetRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
final DistributionSetRepository distributionSetRepository) {
this.distributionSetTagRepository = distributionSetTagRepository;
this.distributionSetRepository = distributionSetRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
}
@Override
@@ -155,8 +148,7 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
@Override
public Page<DistributionSetTag> findByRsql(final String rsql, final Pageable pageable) {
final Specification<JpaDistributionSetTag> spec = RsqlUtility.buildRsqlSpecification(
rsql, DistributionSetTagFields.class, virtualPropertyReplacer, database);
final Specification<JpaDistributionSetTag> spec = RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetTagFields.class);
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.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -67,22 +65,17 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
private final DistributionSetRepository distributionSetRepository;
private final TargetTypeRepository targetTypeRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
private final QuotaManagement quotaManagement;
public JpaDistributionSetTypeManagement(
final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
final QuotaManagement quotaManagement) {
this.distributionSetTypeRepository = distributionSetTypeRepository;
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
this.distributionSetRepository = distributionSetRepository;
this.targetTypeRepository = targetTypeRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
this.quotaManagement = quotaManagement;
}
@@ -198,7 +191,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
@Override
public Page<DistributionSetType> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, DistributionSetTypeFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetTypeFields.class),
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.TotalTargetCountActionStatus;
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.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
@@ -70,24 +68,18 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
private final ActionRepository actionRepository;
private final TargetRepository targetRepository;
private final EntityManager entityManager;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final RolloutStatusCache rolloutStatusCache;
private final Database database;
@SuppressWarnings("java:S107")
public JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
final TargetRepository targetRepository, final EntityManager entityManager,
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
final Database database) {
final TargetRepository targetRepository, final EntityManager entityManager, final RolloutStatusCache rolloutStatusCache) {
this.rolloutGroupRepository = rolloutGroupRepository;
this.rolloutRepository = rolloutRepository;
this.actionRepository = actionRepository;
this.targetRepository = targetRepository;
this.entityManager = entityManager;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.rolloutStatusCache = rolloutStatusCache;
this.database = database;
}
@Override
@@ -122,8 +114,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
final List<Specification<JpaRolloutGroup>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, RolloutGroupFields.class, virtualPropertyReplacer,
database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, RolloutGroupFields.class),
(root, query, cb) -> cb.equal(root.get(JpaRolloutGroup_.rollout).get(AbstractJpaBaseEntity_.id), rolloutId));
return JpaManagementHelper.findAllWithCountBySpec(rolloutGroupRepository, specList, pageable);
@@ -189,7 +180,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
final List<Specification<JpaTarget>> specList = Arrays.asList(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
(root, query, cb) -> {
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup);
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.TotalTargetCountActionStatus;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.springframework.dao.ConcurrencyFailureException;
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.Direction;
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.Retryable;
import org.springframework.scheduling.annotation.Async;
@@ -120,10 +118,8 @@ public class JpaRolloutManagement implements RolloutManagement {
private final TenantConfigurationManagement tenantConfigurationManagement;
private final QuotaManagement quotaManagement;
private final AfterTransactionCommitExecutor afterCommit;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final SystemSecurityContext systemSecurityContext;
private final ContextAware contextAware;
private final Database database;
private final RepositoryProperties repositoryProperties;
@SuppressWarnings("java:S107")
@@ -139,8 +135,7 @@ public class JpaRolloutManagement implements RolloutManagement {
final TenantConfigurationManagement tenantConfigurationManagement,
final QuotaManagement quotaManagement,
final AfterTransactionCommitExecutor afterCommit,
final VirtualPropertyReplacer virtualPropertyReplacer,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final Database database,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware,
final RepositoryProperties repositoryProperties) {
this.rolloutRepository = rolloutRepository;
this.rolloutGroupRepository = rolloutGroupRepository;
@@ -153,10 +148,8 @@ public class JpaRolloutManagement implements RolloutManagement {
this.tenantConfigurationManagement = tenantConfigurationManagement;
this.quotaManagement = quotaManagement;
this.afterCommit = afterCommit;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.systemSecurityContext = systemSecurityContext;
this.contextAware = contextAware;
this.database = database;
this.repositoryProperties = repositoryProperties;
}
@@ -273,7 +266,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override
public Page<Rollout> findByRsql(final String rsql, final boolean deleted, final Pageable pageable) {
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()));
return JpaManagementHelper.convertPage(rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), pageable), pageable);
}
@@ -281,7 +274,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override
public Page<Rollout> findByRsqlWithDetailedStatus(final String rsql, final boolean deleted, final Pageable pageable) {
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()));
return appendStatusDetails(JpaManagementHelper.convertPage(
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.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.AuditorAware;
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.Slice;
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.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -89,8 +87,6 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
private final AuditorAware<String> auditorProvider;
private final ArtifactManagement artifactManagement;
private final QuotaManagement quotaManagement;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
@SuppressWarnings("java:S107")
public JpaSoftwareModuleManagement(final EntityManager entityManager,
@@ -98,9 +94,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
final SoftwareModuleRepository softwareModuleRepository,
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement,
final VirtualPropertyReplacer virtualPropertyReplacer,
final Database database) {
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
this.entityManager = entityManager;
this.distributionSetRepository = distributionSetRepository;
this.softwareModuleRepository = softwareModuleRepository;
@@ -109,8 +103,6 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
this.auditorProvider = auditorProvider;
this.artifactManagement = artifactManagement;
this.quotaManagement = quotaManagement;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
}
@Override
@@ -261,8 +253,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
@Override
public Page<SoftwareModule> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, SoftwareModuleFields.class, virtualPropertyReplacer,
database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, SoftwareModuleFields.class),
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.specifications.SoftwareModuleTypeSpecification;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -51,20 +49,15 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
private final DistributionSetTypeRepository distributionSetTypeRepository;
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final SoftwareModuleRepository softwareModuleRepository;
private final Database database;
public JpaSoftwareModuleTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
public JpaSoftwareModuleTypeManagement(
final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer,
final SoftwareModuleRepository softwareModuleRepository,
final Database database) {
final SoftwareModuleRepository softwareModuleRepository) {
this.distributionSetTypeRepository = distributionSetTypeRepository;
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.softwareModuleRepository = softwareModuleRepository;
this.database = database;
}
@Override
@@ -144,8 +137,7 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
@Override
public Page<SoftwareModuleType> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleTypeRepository, List.of(
RsqlUtility.buildRsqlSpecification(rsql, SoftwareModuleTypeFields.class,
virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, SoftwareModuleTypeFields.class),
SoftwareModuleTypeSpecification.isNotDeleted()), pageable
);
}

View File

@@ -14,7 +14,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import jakarta.persistence.EntityManager;
import jakarta.validation.constraints.NotNull;
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.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
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.Slice;
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.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -77,7 +74,6 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
private final TargetFilterQueryRepository targetFilterQueryRepository;
private final TargetManagement targetManagement;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final DistributionSetManagement distributionSetManagement;
private final QuotaManagement quotaManagement;
private final TenantConfigurationManagement tenantConfigurationManagement;
@@ -85,29 +81,23 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
private final SystemSecurityContext systemSecurityContext;
private final ContextAware contextAware;
private final AuditorAware<String> auditorAware;
private final EntityManager entityManager;
private final Database database;
@SuppressWarnings("java:S107")
public JpaTargetFilterQueryManagement(final TargetFilterQueryRepository targetFilterQueryRepository,
final TargetManagement targetManagement, final VirtualPropertyReplacer virtualPropertyReplacer,
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
final Database database, final TenantConfigurationManagement tenantConfigurationManagement,
public JpaTargetFilterQueryManagement(
final TargetFilterQueryRepository targetFilterQueryRepository,
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigurationManagement,
final RepositoryProperties repositoryProperties,
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware,
final EntityManager entityManager) {
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware) {
this.targetFilterQueryRepository = targetFilterQueryRepository;
this.targetManagement = targetManagement;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.distributionSetManagement = distributionSetManagement;
this.quotaManagement = quotaManagement;
this.database = database;
this.tenantConfigurationManagement = tenantConfigurationManagement;
this.repositoryProperties = repositoryProperties;
this.systemSecurityContext = systemSecurityContext;
this.contextAware = contextAware;
this.auditorAware = auditorAware;
this.entityManager = entityManager;
}
@Override
@@ -119,7 +109,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
create.getQuery().ifPresent(query -> {
// 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
// if the result of the filter query can vary over time
@@ -148,7 +138,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
@Override
public boolean verifyTargetFilterQuerySyntax(final String query) {
try {
RsqlUtility.validateRsqlFor(query, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RsqlUtility.getInstance().validateRsqlFor(query, TargetFields.class, JpaTarget.class);
return true;
} catch (final RSQLParserException | RSQLParameterUnsupportedFieldException e) {
log.debug("The RSQL query '{}}' is invalid.", query, e);
@@ -195,8 +185,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
@Override
public Page<TargetFilterQuery> findByRsql(final String rsqlFilter, final Pageable pageable) {
final List<Specification<JpaTargetFilterQuery>> specList = !ObjectUtils.isEmpty(rsqlFilter)
? Collections.singletonList(RsqlUtility.buildRsqlSpecification(rsqlFilter,
TargetFilterQueryFields.class, virtualPropertyReplacer, database))
? Collections.singletonList(RsqlUtility.getInstance().buildRsqlSpecification(rsqlFilter, TargetFilterQueryFields.class))
: Collections.emptyList();
return JpaManagementHelper.findAllWithCountBySpec(targetFilterQueryRepository, specList, pageable);
@@ -227,8 +216,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
final List<Specification<JpaTargetFilterQuery>> specList = new ArrayList<>(2);
specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet));
if (!ObjectUtils.isEmpty(rsql)) {
specList.add(RsqlUtility.buildRsqlSpecification(rsql, TargetFilterQueryFields.class,
virtualPropertyReplacer, database));
specList.add(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFilterQueryFields.class));
}
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.TargetTypeAssignmentResult;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
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.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -104,8 +102,6 @@ public class JpaTargetManagement implements TargetManagement {
private final TargetFilterQueryRepository targetFilterQueryRepository;
private final TargetTagRepository targetTagRepository;
private final TenantAware tenantAware;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
@SuppressWarnings("java:S107")
public JpaTargetManagement(final EntityManager entityManager,
@@ -114,8 +110,7 @@ public class JpaTargetManagement implements TargetManagement {
final RolloutGroupRepository rolloutGroupRepository,
final TargetFilterQueryRepository targetFilterQueryRepository,
final TargetTagRepository targetTagRepository,
final TenantAware tenantAware, final VirtualPropertyReplacer virtualPropertyReplacer,
final Database database) {
final TenantAware tenantAware) {
this.entityManager = entityManager;
this.distributionSetManagement = distributionSetManagement;
this.quotaManagement = quotaManagement;
@@ -125,8 +120,6 @@ public class JpaTargetManagement implements TargetManagement {
this.targetFilterQueryRepository = targetFilterQueryRepository;
this.targetTagRepository = targetTagRepository;
this.tenantAware = tenantAware;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
}
@Override
@@ -157,22 +150,20 @@ public class JpaTargetManagement implements TargetManagement {
public long countByRsql(final String rsql) {
return JpaManagementHelper.countBySpec(
targetRepository,
List.of(RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database)));
List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class)));
}
@Override
public long countByRsqlAndUpdatable(String rsql) {
final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database));
return targetRepository.count(
AccessController.Operation.UPDATE,
combineWithAnd(specList));
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class));
return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
}
@Override
public long countByRsqlAndCompatible(final String rsql, final Long distributionSetIdTypeId) {
final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
return JpaManagementHelper.countBySpec(targetRepository, specList);
}
@@ -180,7 +171,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public long countByRsqlAndCompatibleAndUpdatable(String rsql, Long distributionSetIdTypeId) {
final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
}
@@ -253,7 +244,7 @@ public class JpaTargetManagement implements TargetManagement {
.findAllWithoutCount(
AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))),
pageable)
@@ -268,8 +259,7 @@ public class JpaTargetManagement implements TargetManagement {
return targetRepository.count(
AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(
rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))));
}
@@ -280,7 +270,7 @@ public class JpaTargetManagement implements TargetManagement {
return targetRepository
.findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))),
pageable)
@@ -292,7 +282,7 @@ public class JpaTargetManagement implements TargetManagement {
final String rsql, final Collection<Long> groups, final DistributionSetType dsType) {
return targetRepository.count(AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
}
@@ -319,7 +309,7 @@ public class JpaTargetManagement implements TargetManagement {
return targetRepository
.findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasNoOverridingActionsAndNotInRollout(rolloutId),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetType.getId()))),
pageable)
@@ -355,7 +345,7 @@ public class JpaTargetManagement implements TargetManagement {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId()));
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable);
@@ -395,7 +385,7 @@ public class JpaTargetManagement implements TargetManagement {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId()));
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) {
return JpaManagementHelper.findAllWithoutCountBySpec(
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));
return JpaManagementHelper.findAllWithoutCountBySpec(
targetRepository, List.of(RsqlUtility.buildRsqlSpecification(
targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyReplacer, database)), pageable
targetRepository, List.of(RsqlUtility.getInstance().buildRsqlSpecification(
targetFilterQuery.getQuery(), TargetFields.class)), pageable
);
}
@@ -442,7 +432,7 @@ public class JpaTargetManagement implements TargetManagement {
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(rsql, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
TargetSpecifications.hasTag(tagId));
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable);
@@ -611,12 +601,12 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
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)
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distributionSetId));
final Long distSetTypeId = ds.getType().getId();
final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
RsqlUtility.getInstance().buildRsqlSpecification(targetFilterQuery, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId),
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.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -48,16 +46,8 @@ public class JpaTargetTagManagement implements TargetTagManagement {
private final TargetTagRepository targetTagRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
public JpaTargetTagManagement(
final TargetTagRepository targetTagRepository,
final VirtualPropertyReplacer virtualPropertyReplacer,
final Database database) {
this.targetTagRepository = targetTagRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
public JpaTargetTagManagement(final TargetTagRepository targetTagRepository) {
this.targetTagRepository = targetTagRepository;;
}
@Override
@@ -105,7 +95,7 @@ public class JpaTargetTagManagement implements TargetTagManagement {
@Override
public Page<TargetTag> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(targetTagRepository, Collections.singletonList(
RsqlUtility.buildRsqlSpecification(rsql, TargetTagFields.class, virtualPropertyReplacer, database)), pageable);
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetTagFields.class)), pageable);
}
@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.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional;
@@ -60,9 +58,6 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
private final TargetRepository targetRepository;
private final DistributionSetTypeRepository distributionSetTypeRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
private final QuotaManagement quotaManagement;
/**
@@ -70,18 +65,13 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
*
* @param targetTypeRepository Target type repository
* @param targetRepository Target repository
* @param virtualPropertyReplacer replacer
* @param database database
*/
public JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository,
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
final QuotaManagement quotaManagement) {
this.targetTypeRepository = targetTypeRepository;
this.targetRepository = targetRepository;
this.distributionSetTypeRepository = distributionSetTypeRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.database = database;
this.quotaManagement = quotaManagement;
}
@@ -145,10 +135,10 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
@Override
public Page<TargetType> findByRsql(final String rsql, final Pageable pageable) {
return JpaManagementHelper.findAllWithCountBySpec(targetTypeRepository, List.of(
RsqlUtility.buildRsqlSpecification(
rsql, TargetTypeFields.class, virtualPropertyReplacer, database)), pageable
);
return JpaManagementHelper.findAllWithCountBySpec(
targetTypeRepository,
List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetTypeFields.class)),
pageable);
}
@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.assertThatExceptionOfType;
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.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.TargetTypeAssignmentResult;
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.ExpectEvents;
import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
@@ -1091,7 +1091,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
*/
@Test
void findTargetsByRsqlWithTypeAndMetadata() {
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G1) {
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G1) {
// legacy visitor fail with that
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.assertThatExceptionOfType;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlConfigHolder.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_G2;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import java.util.Arrays;
import java.util.Map;
import jakarta.persistence.EntityManager;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TargetTypeFields;
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.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Slice;
/**
@@ -45,11 +41,6 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
private static final String OR = ",";
private static final String AND = ";";
@Autowired
protected VirtualPropertyReplacer virtualPropertyReplacer;
@Autowired
protected EntityManager entityManager;
private Target target;
private Target target2;
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.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.null=is=null", 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.n/a!=null", 0); // "null" check
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
assertRSQLQuery(
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=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.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=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
}
@@ -315,7 +306,7 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 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=null", 4); // null check (1 of the initial five has)
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() + ".metaKey!=notExist", 2);
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
assertRSQLQuery(
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() + ".notExist=not=metaValue",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=not=notExist",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
assertRSQLQuery(
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() + ".notExist=ne=metaValue",
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
assertRSQLQuery(
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);
@@ -386,28 +377,26 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
*/
@Test
void rsqlValidTargetFields() {
RsqlUtility.validateRsqlFor(
RsqlUtility.getInstance().validateRsqlFor(
"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 tag == beta",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RsqlUtility.validateRsqlFor(
TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor(
"ASSIGNEDDS.name == abcd and ASSIGNEDDS.version == 0123 and INSTALLEDDS.name == abcd and INSTALLEDDS.version == 0123",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RsqlUtility.validateRsqlFor(
TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor(
"ATTRIBUTE.subkey1 == test and ATTRIBUTE.subkey2 == test and METADATA.metakey1 == abcd and METADATA.metavalue2 == asdfg",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RsqlUtility.validateRsqlFor(
TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor(
"CREATEDAT =lt= ${NOW_TS} and LASTMODIFIEDAT =ge= ${OVERDUE_TS}",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RsqlUtility.validateRsqlFor(
TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor(
"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)
.isThrownBy(() -> RsqlUtility.validateRsqlFor(
"wrongfield == abcd",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager));
.isThrownBy(() -> RsqlUtility.getInstance().validateRsqlFor("wrongfield == abcd", TargetFields.class, JpaTarget.class));
}
/**
@@ -452,7 +441,6 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
private void assertRSQLQueryThrowsException(final String rsql) {
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> RsqlUtility.validateRsqlFor(
rsql, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager));
.isThrownBy(() -> RsqlUtility.getInstance().validateRsqlFor(rsql, TargetFields.class, JpaTarget.class));
}
}

View File

@@ -9,9 +9,9 @@
*/
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.RsqlConfigHolder.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_G2;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.G3;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
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();
}
}
}