From 1d690261843d15e6a43a1d8cbf390d38781997cd Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Mon, 29 Aug 2016 12:54:36 +0200 Subject: [PATCH 01/17] Overdue target filter based on makro resolution of placeholders Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../RepositoryApplicationConfiguration.java | 44 +++--- .../jpa/JpaTargetFilterQueryManagement.java | 6 +- .../repository/jpa/JpaTargetManagement.java | 26 +++- .../repository/jpa/rsql/RSQLUtility.java | 66 +++++++-- .../rsql/VirtualPropertyMakroResolver.java | 71 ++++++++++ .../repository/jpa/rsql/RSQLUtilityTest.java | 134 ++++++++++++++---- .../VirtualPropertyMakroResolverTest.java | 114 +++++++++++++++ 7 files changed, 397 insertions(+), 64 deletions(-) create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolverTest.java diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java index a62de9a06..50a3d0b48 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java @@ -52,6 +52,7 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyMakroResolver; import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -162,7 +163,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { } /** - * + * * @return the singleton instance of the * {@link AfterTransactionCommitExecutorHolder} */ @@ -225,7 +226,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaSystemManagement} bean. - * + * * @return a new {@link SystemManagement} */ @Bean @@ -236,7 +237,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaReportManagement} bean. - * + * * @return a new {@link ReportManagement} */ @Bean @@ -247,7 +248,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaDistributionSetManagement} bean. - * + * * @return a new {@link DistributionSetManagement} */ @Bean @@ -258,7 +259,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaTenantStatsManagement} bean. - * + * * @return a new {@link TenantStatsManagement} */ @Bean @@ -271,7 +272,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaTenantConfigurationManagement} bean. - * + * * @return a new {@link TenantConfigurationManagement} */ @Bean @@ -282,7 +283,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaTenantConfigurationManagement} bean. - * + * * @return a new {@link TenantConfigurationManagement} */ @Bean @@ -293,7 +294,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaTargetFilterQueryManagement} bean. - * + * * @return a new {@link TargetFilterQueryManagement} */ @Bean @@ -304,7 +305,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaTagManagement} bean. - * + * * @return a new {@link TagManagement} */ @Bean @@ -315,7 +316,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaSoftwareManagement} bean. - * + * * @return a new {@link SoftwareManagement} */ @Bean @@ -326,7 +327,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaRolloutManagement} bean. - * + * * @return a new {@link RolloutManagement} */ @Bean @@ -337,7 +338,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaRolloutGroupManagement} bean. - * + * * @return a new {@link RolloutGroupManagement} */ @Bean @@ -348,7 +349,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaDeploymentManagement} bean. - * + * * @return a new {@link DeploymentManagement} */ @Bean @@ -359,7 +360,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaControllerManagement} bean. - * + * * @return a new {@link ControllerManagement} */ @Bean @@ -370,7 +371,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaArtifactManagement} bean. - * + * * @return a new {@link ArtifactManagement} */ @@ -382,7 +383,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * {@link JpaEntityFactory} bean. - * + * * @return a new {@link EntityFactory} */ @Bean @@ -390,4 +391,15 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { public EntityFactory entityFactory() { return new JpaEntityFactory(); } + + /** + * {@link VirtualPropertyMakroResolver} bean. + * + * @return a new {@link VirtualPropertyMakroResolver} + */ + @Bean + @ConditionalOnMissingBean + public VirtualPropertyMakroResolver virtualPropertyMakroResolver() { + return new VirtualPropertyMakroResolver(); + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java index 6438e19f6..693f9395e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java @@ -16,6 +16,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyMakroResolver; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; @@ -44,6 +45,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme @Autowired private TargetFilterQueryRepository targetFilterQueryRepository; + @Autowired + private VirtualPropertyMakroResolver virtualPropMakroResolver; + @Override @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) @@ -111,7 +115,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme @Override public boolean verifyTargetFilterQuerySyntax(final String query) { - RSQLUtility.parse(query, TargetFields.class); + RSQLUtility.parse(query, TargetFields.class, virtualPropMakroResolver); return true; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 225c0b4b2..b901ee6df 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -41,6 +41,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyMakroResolver; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.model.Target; @@ -102,6 +103,9 @@ public class JpaTargetManagement implements TargetManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; + @Autowired + private VirtualPropertyMakroResolver virtualPropMakroResolver; + @Override public Target findTargetByControllerID(final String controllerId) { return targetRepository.findByControllerId(controllerId); @@ -152,12 +156,15 @@ public class JpaTargetManagement implements TargetManagement { @Override public Slice findTargetsAll(final TargetFilterQuery targetFilterQuery, final Pageable pageable) { - return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class), pageable); + return findTargetsBySpec( + RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropMakroResolver), + pageable); } @Override public Page findTargetsAll(final String targetFilterQuery, final Pageable pageable) { - return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class), pageable); + return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class, virtualPropMakroResolver), + pageable); } private Page findTargetsBySpec(final Specification spec, final Pageable pageable) { @@ -224,7 +231,8 @@ public class JpaTargetManagement implements TargetManagement { public Page findTargetByAssignedDistributionSet(final Long distributionSetID, final String rsqlParam, final Pageable pageReq) { - final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class, + virtualPropMakroResolver); return convertPage( targetRepository @@ -252,7 +260,8 @@ public class JpaTargetManagement implements TargetManagement { public Page findTargetByInstalledDistributionSet(final Long distributionSetId, final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class, + virtualPropMakroResolver); return convertPage( targetRepository @@ -544,7 +553,8 @@ public class JpaTargetManagement implements TargetManagement { final CriteriaQuery multiselect = query.multiselect(targetRoot.get(JpaTarget_.id), targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty)); - final Specification spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class); + final Specification spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, + virtualPropMakroResolver); final List> specList = new ArrayList<>(); specList.add(spec); @@ -627,13 +637,15 @@ public class JpaTargetManagement implements TargetManagement { @Override public Long countTargetByTargetFilterQuery(final TargetFilterQuery targetFilterQuery) { - final Specification specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class); + final Specification specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, + virtualPropMakroResolver); return targetRepository.count(specs); } @Override public Long countTargetByTargetFilterQuery(final String targetFilterQuery) { - final Specification specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class); + final Specification specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class, + virtualPropMakroResolver); return targetRepository.count(specs); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index 90dd039f5..228091494 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -25,6 +25,8 @@ import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import org.apache.commons.lang3.text.StrLookup; +import org.apache.commons.lang3.text.StrSubstitutor; import org.eclipse.hawkbit.repository.FieldNameProvider; import org.eclipse.hawkbit.repository.FieldValueConverter; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; @@ -47,9 +49,8 @@ import cz.jirutka.rsql.parser.ast.RSQLOperators; import cz.jirutka.rsql.parser.ast.RSQLVisitor; /** - * A utility class which is able to parse RSQL strings into an spring data - * {@link Specification} which then can be enhanced sql queries to filter - * entities. RSQL parser library: https://github.com/jirutka/rsql-parser + * A utility class which is able to parse RSQL strings into an spring data {@link Specification} which then can be + * enhanced sql queries to filter entities. RSQL parser library: https://github.com/jirutka/rsql-parser * *
    *
  • Equal to : ==
  • @@ -59,16 +60,24 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor; *
  • Greater than operator : =gt= or >
  • *
  • Greater than or equal to : =ge= or >=
  • *
+ *

* Examples of RSQL expressions in both FIQL-like and alternative notation: *

    *
  • version==2.0.0
  • *
  • name==targetId1;description==plugAndPlay
  • *
  • name==targetId1 and description==plugAndPlay
  • - *
  • name==targetId1;description==plugAndPlay
  • - *
  • name==targetId1 and description==plugAndPlay
  • *
  • name==targetId1,description==plugAndPlay,updateStatus==UNKNOWN
  • *
  • name==targetId1 or description==plugAndPlay or updateStatus==UNKNOWN
  • *
+ *

+ * There is also a mechanism that allows to refer to known makros that can resolved by an optional {@link StrLookup} + * (cp. {@link VirtualPropertyMakroResolver}).
+ * An example that queries for all overdue targets using the ${OVERDUE_TS} placeholder introduced by + * {@link VirtualPropertyMakroResolver} looks like this:
+ * lastControllerRequestAt=le=${OVERDUE_TS}
+ * It is possible to escape a makro expression by using a second '$': $${OVERDUE_TS} would prevent the ${OVERDUE_TS} + * token from being expanded. + * */ public final class RSQLUtility { @@ -99,7 +108,28 @@ public final class RSQLUtility { */ public static & FieldNameProvider, T> Specification parse(final String rsql, final Class fieldNameProvider) { - return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider); + return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, new VirtualPropertyMakroResolver()); + } + + /** + * parses an RSQL valid string into an JPA {@link Specification} which then can be used to filter for JPA entities + * with the given RSQL query. + * + * @param rsql + * the rsql query + * @param fieldNameProvider + * the enum class type which implements the {@link FieldNameProvider} + * @param makroLookup + * holds the logic how the known makros have to be resolved; may be null + * @return an 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 & FieldNameProvider, T> Specification parse(final String rsql, + final Class fieldNameProvider, StrLookup makroLookup) { + return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, makroLookup); } /** @@ -130,10 +160,12 @@ public final class RSQLUtility { private final String rsql; private final Class enumType; + private final StrLookup makroLookup; - private RSQLSpecification(final String rsql, final Class enumType) { + private RSQLSpecification(final String rsql, final Class enumType, StrLookup makroLookup) { this.rsql = rsql; this.enumType = enumType; + this.makroLookup = makroLookup; } @Override @@ -141,7 +173,8 @@ public final class RSQLUtility { final Node rootNode = parseRsql(rsql); - final JpqQueryRSQLVisitor jpqQueryRSQLVisitor = new JpqQueryRSQLVisitor<>(root, cb, enumType); + final JpqQueryRSQLVisitor jpqQueryRSQLVisitor = new JpqQueryRSQLVisitor<>(root, cb, enumType, + makroLookup); final List accept = rootNode., String> accept(jpqQueryRSQLVisitor); if (accept != null && !accept.isEmpty()) { @@ -171,13 +204,19 @@ public final class RSQLUtility { private final Root root; private final CriteriaBuilder cb; private final Class enumType; + private final StrLookup makroLookup; + private final StrSubstitutor substitutor; private final SimpleTypeConverter simpleTypeConverter; - private JpqQueryRSQLVisitor(final Root root, final CriteriaBuilder cb, final Class enumType) { + private JpqQueryRSQLVisitor(final Root root, final CriteriaBuilder cb, final Class enumType, + StrLookup makroLookup) { this.root = root; this.cb = cb; this.enumType = enumType; + this.makroLookup = makroLookup; + this.substitutor = new StrSubstitutor(makroLookup, StrSubstitutor.DEFAULT_PREFIX, + StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); simpleTypeConverter = new SimpleTypeConverter(); } @@ -425,7 +464,14 @@ public final class RSQLUtility { // enums. The JPA API // cannot handle object types for greaterThan etc methods. final Object transformedValue = transformedValues.get(0); - final String value = values.get(0); + + final String value; + if (makroLookup != null) { // if substitutor is available, replace makros ... + value = substitutor.replace(values.get(0)); + } else { + value = values.get(0); + } + final List singleList = new ArrayList<>(); final Predicate mapPredicate = mapToMapPredicate(node, fieldPath, enumField); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java new file mode 100644 index 000000000..8425e4a11 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2016 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.rsql; + +import java.time.Duration; +import java.time.Instant; + +import org.apache.commons.lang3.text.StrLookup; +import org.apache.commons.lang3.text.StrSubstitutor; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; +import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; + +/** + * Adds makro capabilities to RSQL expressions that are used to filter for targets. + *

+ * Some (virtual) properties do not have a representation in the database (in general these properties are time-related, + * or more explicitly, they deal with time intervals).
+ * Such a virtual property needs to be calculated on Java-side before it may be used in a target filter query that is + * passed to the database. Therefore a placeholder is used in the RSQL expression that is expanded in the + * {@link RSQLUtility} by a {@link StrSubstitutor}. This {@link StrSubstitutor} is configured with an instance of + * {@link VirtualPropertyMakroResolver} to resolve the known makros. + *

+ * A virtual property may either be a system value like the current date (aka now_ts) or a value derived from + * (tenant-specific) system configuration (e.g. overdue_ts). + *

+ * Known values are:
+ *

+ * + */ +public class VirtualPropertyMakroResolver extends StrLookup { + + @Override + public String lookup(String rhs) { + String resolved = null; + + if ("now_ts".equals(rhs.toLowerCase())) { + resolved = String.valueOf(Instant.now().toEpochMilli()); + } else if ("overdue_ts".equals(rhs.toLowerCase())) { + resolved = String.valueOf(Instant.now().toEpochMilli() // + - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() // + - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis()); + } + return resolved; + } + + private Duration getDurationForKey(TenantConfigurationKey key) { + return DurationHelper.formattedStringToDuration(getRawStringForKey(key)); + } + + private String getRawStringForKey(TenantConfigurationKey key) { + return getTenantConfigurationManagement().getConfigurationValue(key, String.class).getValue(); + } + + TenantConfigurationManagement getTenantConfigurationManagement() { + return TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement(); + } + + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index 04901d948..e7b5ba592 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -9,14 +9,8 @@ package org.eclipse.hawkbit.repository.jpa.rsql; import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -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 static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -26,18 +20,24 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.persistence.metamodel.Attribute; +import org.apache.commons.lang3.text.StrLookup; import org.eclipse.hawkbit.repository.DistributionSetFields; import org.eclipse.hawkbit.repository.FieldNameProvider; import org.eclipse.hawkbit.repository.SoftwareModuleFields; import org.eclipse.hawkbit.repository.TargetFields; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; 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.tenancy.configuration.TenantConfigurationKey; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; +import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; @@ -48,6 +48,12 @@ import ru.yandex.qatools.allure.annotations.Stories; // method name as short text public class RSQLUtilityTest { + @Spy + VirtualPropertyMakroResolver makroResolver = new VirtualPropertyMakroResolver(); + + @Mock + TenantConfigurationManagement confMgmt; + @Mock private Root baseSoftwareModuleRootMock; @@ -59,11 +65,16 @@ public class RSQLUtilityTest { @Mock private Attribute attribute; + private static final TenantConfigurationValue TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue + .builder().value("00:05:00").build(); + private static final TenantConfigurationValue TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue + .builder().value("00:07:37").build(); + @Test public void wrongRsqlSyntaxThrowSyntaxException() { final String wrongRSQL = "name==abc;d"; try { - RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterSyntaxException e) { @@ -75,7 +86,7 @@ public class RSQLUtilityTest { final String wrongRSQL = "unknownField==abc"; when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); try { - RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing an expected RSQLParameterUnsupportedFieldException because of unknown RSQL field"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -87,7 +98,8 @@ public class RSQLUtilityTest { public void wrongRsqlMapSyntaxThrowSyntaxException() { String wrongRSQL = TargetFields.ATTRIBUTE + "==abc"; try { - RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, + RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -95,7 +107,8 @@ public class RSQLUtilityTest { wrongRSQL = TargetFields.ATTRIBUTE + ".unkwon.wrong==abc"; try { - RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, + RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -103,7 +116,7 @@ public class RSQLUtilityTest { wrongRSQL = DistributionSetFields.METADATA + "==abc"; try { - RSQLUtility.parse(wrongRSQL, DistributionSetFields.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(wrongRSQL, DistributionSetFields.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -115,7 +128,8 @@ public class RSQLUtilityTest { public void wrongRsqlSubEntitySyntaxThrowSyntaxException() { String wrongRSQL = TargetFields.ASSIGNEDDS + "==abc"; try { - RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, + RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -123,7 +137,8 @@ public class RSQLUtilityTest { wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField==abc"; try { - RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, + RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -131,7 +146,8 @@ public class RSQLUtilityTest { wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField.ToMuch==abc"; try { - RSQLUtility.parse(wrongRSQL, TargetFields.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, + RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -146,11 +162,11 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("version")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); // test - RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); // verfication @@ -164,12 +180,12 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); // test - RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); // verfication @@ -185,12 +201,12 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); // test - RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); // verfication @@ -206,10 +222,10 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); // test - RSQLUtility.parse(correctRsql, SoftwareModuleFields.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); // verfication @@ -226,7 +242,8 @@ public class RSQLUtilityTest { when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); // test - RSQLUtility.parse(correctRsql, TestFieldEnum.class).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, + RSQLUtility.parse(correctRsql, TestFieldEnum.class, null).toPredicate(baseSoftwareModuleRootMock, + criteriaQueryMock, criteriaBuilderMock); // verfication @@ -244,7 +261,7 @@ public class RSQLUtilityTest { try { // test - RSQLUtility.parse(correctRsql, TestFieldEnum.class).toPredicate(baseSoftwareModuleRootMock, + RSQLUtility.parse(correctRsql, TestFieldEnum.class, null).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("missing RSQLParameterUnsupportedFieldException for wrong enum value"); } catch (final RSQLParameterUnsupportedFieldException e) { @@ -252,6 +269,65 @@ public class RSQLUtilityTest { } } + @Test + @Description("Tests the resolution of overdue_ts placeholder in context of a RSQL expression.") + public void correctRsqlWithOverdueMakro() { + reset(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.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); + when(criteriaBuilderMock.lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) + .thenReturn(mock(Predicate.class)); + + // test + Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMakroLookup()) + .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); + + // verfication + verify(makroResolver, times(1)).lookup(overdueProp); + // the makro is already replaced when passed to #lessThanOrEqualTo -> the method is never invoked with the + // placeholder: + verify(criteriaBuilderMock, never()).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), + eq(overduePropPlaceholder)); + } + + @Test + @Description("Tests RSQL expression with an unknown placeholder.") + public void correctRsqlWithUnknownMakro() { + reset(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.lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) + .thenReturn(mock(Predicate.class)); + + // test + Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMakroLookup()) + .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); + + // verfication + verify(makroResolver, times(1)).lookup(overdueProp); + // the makro is unknown and hence never replaced -> #lessThanOrEqualTo is invoked with the placeholder: + verify(criteriaBuilderMock, times(1)).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), + eq(overduePropPlaceholder)); + } + + public StrLookup setupMakroLookup() { + when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class)) + .thenReturn(TEST_POLLING_TIME_INTERVAL); + when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) + .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); + when(makroResolver.getTenantConfigurationManagement()).thenReturn(confMgmt); + + return makroResolver; + } + @SuppressWarnings("unchecked") private Path pathOfString(final Path path) { return (Path) path; @@ -262,10 +338,8 @@ public class RSQLUtilityTest { /* * (non-Javadoc) - * - * @see - * org.eclipse.hawkbit.server.rest.resource.model.FieldNameProvider# - * getFieldName() + * + * @see org.eclipse.hawkbit.server.rest.resource.model.FieldNameProvider# getFieldName() */ @Override public String getFieldName() { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolverTest.java new file mode 100644 index 000000000..f18783d5f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolverTest.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2016 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.rsql; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +import java.time.Instant; + +import org.apache.commons.lang3.text.StrSubstitutor; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; + +import ru.yandex.qatools.allure.annotations.Description; +import ru.yandex.qatools.allure.annotations.Features; +import ru.yandex.qatools.allure.annotations.Stories; + +@Features("Unit Tests - Repository") +@Stories("Placeholder resolution for virtual properties") +@RunWith(MockitoJUnitRunner.class) +public class VirtualPropertyMakroResolverTest { + + @Spy + VirtualPropertyMakroResolver resolverUnderTest = new VirtualPropertyMakroResolver(); + + @Mock + TenantConfigurationManagement confMgmt; + + StrSubstitutor substitutor; + + Long nowTestTime; + + private static final TenantConfigurationValue TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue + . builder().value("00:05:00").build(); + private static final TenantConfigurationValue TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue + . builder().value("00:07:37").build(); + + @Before + public void before() { + nowTestTime = Instant.now().toEpochMilli(); + when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class)) + .thenReturn(TEST_POLLING_TIME_INTERVAL); + when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) + .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); + when(resolverUnderTest.getTenantConfigurationManagement()).thenReturn(confMgmt); + + this.substitutor = new StrSubstitutor(resolverUnderTest, StrSubstitutor.DEFAULT_PREFIX, + StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); + } + + @Test + @Description("Tests resolution of NOW_TS by using a StrSubstitutor configured with the VirtualPropertyMakroResolver.") + public void resolveNowTimestampPlaceholder() { + String placeholder = "${NOW_TS}"; + String testString = "lhs=lt=" + placeholder; + + String resolvedPlaceholders = substitutor.replace(testString); + assertFalse(resolvedPlaceholders.contains(placeholder)); + } + + @Test + @Description("Tests resolution of OVERDUE_TS by using a StrSubstitutor configured with the VirtualPropertyMakroResolver.") + public void resolveOverdueTimestampPlaceholder() { + String placeholder = "${OVERDUE_TS}"; + String testString = "lhs=lt=" + placeholder; + + String resolvedPlaceholders = substitutor.replace(testString); + assertFalse(resolvedPlaceholders.contains(placeholder)); + } + + @Test + @Description("Tests case insensititity of VirtualPropertyMakroResolver.") + public void resolveOverdueTimestampPlaceholderLowerCase() { + String placeholder = "${overdue_ts}"; + String testString = "lhs=lt=" + placeholder; + + String resolvedPlaceholders = substitutor.replace(testString); + assertFalse(resolvedPlaceholders.contains(placeholder)); + } + + @Test + @Description("Tests VirtualPropertyMakroResolver with a placeholder unknown to VirtualPropertyMakroResolver.") + public void handleUnknownPlaceholder() { + String placeholder = "${unknown}"; + String testString = "lhs=lt=" + placeholder; + + String resolvedPlaceholders = substitutor.replace(testString); + assertTrue(resolvedPlaceholders.contains(placeholder)); + } + + @Test + @Description("Tests escape mechanism for placeholders (syntax is $${SOME_PLACEHOLDER}).") + public void handleEscapedPlaceholder() { + String placeholder = "${OVERDUE_TS}"; + String escaptedPlaceholder = StrSubstitutor.DEFAULT_ESCAPE + placeholder; + String testString = "lhs=lt=" + escaptedPlaceholder; + + String resolvedPlaceholders = substitutor.replace(testString); + assertTrue(resolvedPlaceholders.contains(placeholder)); + } +} From 2433742abf592354342d63d37bc5d6f44b988ede Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Wed, 7 Sep 2016 11:29:01 +0200 Subject: [PATCH 02/17] Overdue filter: Add simple filter for overdue in UI Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../hawkbit/repository/TargetManagement.java | 38 +- .../repository/jpa/JpaTargetManagement.java | 29 +- .../rsql/VirtualPropertyMakroResolver.java | 11 +- .../specifications/TargetSpecifications.java | 36 +- .../jpa/TargetManagementSearchTest.java | 345 ++++--- .../repository/jpa/TargetManagementTest.java | 11 +- .../dstable/DistributionSetTable.java | 2 +- .../management/event/ManagementUIEvent.java | 19 +- .../management/event/TargetFilterEvent.java | 11 +- .../management/footer/CountMessageLabel.java | 13 + .../management/state/TargetTableFilters.java | 13 +- .../targettable/TargetBeanQuery.java | 20 +- .../management/targettable/TargetTable.java | 18 +- .../targettag/FilterByStatusLayout.java | 47 +- .../ui/utils/SPUIComponentIdProvider.java | 846 ++++++++++++++++++ .../hawkbit/ui/utils/SPUIDefinitions.java | 8 +- .../hawkbit/customstyles/filter-status.scss | 19 +- .../customstyles/hawkbitvariables.scss | 4 +- .../themes/hawkbit/customstyles/others.scss | 4 +- .../customstyles/target-filter-query.scss | 2 +- .../src/main/resources/messages.properties | 5 +- .../src/main/resources/messages_de.properties | 5 +- .../src/main/resources/messages_en.properties | 5 +- 23 files changed, 1328 insertions(+), 183 deletions(-) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 5fdfb318e..40fd7cc27 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -67,7 +67,11 @@ public interface TargetManagement { * Count {@link Target}s for all the given filter parameters. * * @param status - * find targets having on of these {@link TargetUpdateStatus}s. + * find targets having one of these {@link TargetUpdateStatus}s. + * Set to null in case this is not required. + * @param overdueState + * find targets that are overdue (targets that did not respond + * during the configured intervals: poll_itvl + overdue_itvl). * Set to null in case this is not required. * @param searchText * to find targets having the text anywhere in name or @@ -86,7 +90,7 @@ public interface TargetManagement { * @return the found number {@link Target}s */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) - Long countTargetByFilters(Collection status, String searchText, + Long countTargetByFilters(Collection status, Boolean overdueState, String searchText, Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames); /** @@ -203,10 +207,12 @@ public interface TargetManagement { * * @param pageRequest * the pageRequest to enhance the query for paging and sorting - * * @param filterByStatus * find targets having this {@link TargetUpdateStatus}s. Set to * null in case this is not required. + * @param overdueState + * find targets that are overdue (targets that did not respond + * during the configured intervals: poll_itvl + overdue_itvl). * @param filterBySearchText * to find targets having the text anywhere in name or * description. Set null in case this is not @@ -225,7 +231,7 @@ public interface TargetManagement { */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) List findAllTargetIdsByFilters(@NotNull Pageable pageRequest, - Collection filterByStatus, String filterBySearchText, + Collection filterByStatus, Boolean overdueState, String filterBySearchText, Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... filterByTagNames); /** @@ -274,7 +280,7 @@ public interface TargetManagement { * given {@code fieldNameProvider} * @throws RSQLParameterSyntaxException * if the RSQL syntax is wrong - * + * */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) Page findTargetByAssignedDistributionSet(@NotNull Long distributionSetID, @NotNull String rsqlParam, @@ -328,6 +334,9 @@ public interface TargetManagement { * @param status * find targets having this {@link TargetUpdateStatus}s. Set to * null in case this is not required. + * @param overdueState + * find targets that are overdue (targets that did not respond + * during the configured intervals: poll_itvl + overdue_itvl). * @param searchText * to find targets having the text anywhere in name or * description. Set null in case this is not @@ -346,7 +355,7 @@ public interface TargetManagement { */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Slice findTargetByFilters(@NotNull Pageable pageable, Collection status, - String searchText, Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, + Boolean overdueState, String searchText, Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames); /** @@ -375,7 +384,7 @@ public interface TargetManagement { * @param pageable * page parameter * @return the found {@link Target}s, never {@code null} - * + * * @throws RSQLParameterUnsupportedFieldException * if a field in the RSQL string is used but not provided by the * given {@code fieldNameProvider} @@ -420,9 +429,9 @@ public interface TargetManagement { * in string notation * @param pageable * pagination parameter - * + * * @return the found {@link Target}s, never {@code null} - * + * * @throws RSQLParameterUnsupportedFieldException * if a field in the RSQL string is used but not provided by the * given {@code fieldNameProvider} @@ -441,9 +450,9 @@ public interface TargetManagement { * the specification for the query * @param pageable * pagination parameter - * + * * @return the found {@link Target}s, never {@code null} - * + * * @throws RSQLParameterUnsupportedFieldException * if a field in the RSQL string is used but not provided by the * given {@code fieldNameProvider} @@ -477,6 +486,9 @@ public interface TargetManagement { * @param filterByStatus * find targets having this {@link TargetUpdateStatus}s. Set to * null in case this is not required. + * @param overdueState + * find targets that are overdue (targets that did not respond + * during the configured intervals: poll_itvl + overdue_itvl). * @param filterBySearchText * to find targets having the text anywhere in name or * description. Set null in case this is not @@ -496,8 +508,8 @@ public interface TargetManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Slice findTargetsAllOrderByLinkedDistributionSet(@NotNull Pageable pageable, @NotNull Long orderByDistributionId, Long filterByDistributionId, - Collection filterByStatus, String filterBySearchText, Boolean selectTargetWithNoTag, - String... filterByTagNames); + Collection filterByStatus, Boolean overdueState, String filterBySearchText, + Boolean selectTargetWithNoTag, String... filterByTagNames); /** * retrieves a list of {@link Target}s by their controller ID with details, diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index b901ee6df..2528ed5ac 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -279,29 +279,33 @@ public class JpaTargetManagement implements TargetManagement { @Override public Slice findTargetByFilters(final Pageable pageable, final Collection status, - final String searchText, final Long installedOrAssignedDistributionSetId, + final Boolean overdueState, final String searchText, final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, final String... tagNames) { - final List> specList = buildSpecificationList(status, searchText, + final List> specList = buildSpecificationList(status, overdueState, searchText, installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); return findByCriteriaAPI(pageable, specList); } @Override - public Long countTargetByFilters(final Collection status, final String searchText, - final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, - final String... tagNames) { - final List> specList = buildSpecificationList(status, searchText, + public Long countTargetByFilters(final Collection status, final Boolean overdueState, + final String searchText, final Long installedOrAssignedDistributionSetId, + final Boolean selectTargetWithNoTag, final String... tagNames) { + final List> specList = buildSpecificationList(status, overdueState, searchText, installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); return countByCriteriaAPI(specList); } private static List> buildSpecificationList(final Collection status, - final String searchText, final Long installedOrAssignedDistributionSetId, + final Boolean overdueState, final String searchText, final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, final boolean fetch, final String... tagNames) { final List> specList = new ArrayList<>(); if (status != null && !status.isEmpty()) { specList.add(TargetSpecifications.hasTargetUpdateStatus(status, fetch)); } + if (overdueState != null) { + specList.add( + TargetSpecifications.isOverdue(new VirtualPropertyMakroResolver().calculateOverdueTimestamp())); + } if (installedOrAssignedDistributionSetId != null) { specList.add( TargetSpecifications.hasInstalledOrAssignedDistributionSet(installedOrAssignedDistributionSetId)); @@ -425,7 +429,8 @@ public class JpaTargetManagement implements TargetManagement { @Override public Slice findTargetsAllOrderByLinkedDistributionSet(final Pageable pageable, final Long orderByDistributionId, final Long filterByDistributionId, - final Collection filterByStatus, final String filterBySearchText, + final Collection filterByStatus, final Boolean overdueState, + final String filterBySearchText, final Boolean selectTargetWithNoTag, final String... filterByTagNames) { final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery(JpaTarget.class); @@ -449,7 +454,7 @@ public class JpaTargetManagement implements TargetManagement { // build the specifications and then to predicates necessary by the // given filters final Predicate[] specificationsForMultiSelect = specificationsToPredicate( - buildSpecificationList(filterByStatus, filterBySearchText, filterByDistributionId, + buildSpecificationList(filterByStatus, overdueState, filterBySearchText, filterByDistributionId, selectTargetWithNoTag, true, filterByTagNames), targetRoot, query, cb); @@ -506,7 +511,8 @@ public class JpaTargetManagement implements TargetManagement { @Override public List findAllTargetIdsByFilters(final Pageable pageRequest, - final Collection filterByStatus, final String filterBySearchText, + final Collection filterByStatus, final Boolean overdueState, + final String filterBySearchText, final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, final String... filterByTagNames) { final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); @@ -523,7 +529,8 @@ public class JpaTargetManagement implements TargetManagement { targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty)); final Predicate[] specificationsForMultiSelect = specificationsToPredicate( - buildSpecificationList(filterByStatus, filterBySearchText, installedOrAssignedDistributionSetId, + buildSpecificationList(filterByStatus, overdueState, filterBySearchText, + installedOrAssignedDistributionSetId, selectTargetWithNoTag, false, filterByTagNames), targetRoot, multiselect, cb); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java index 8425e4a11..5ade64630 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java @@ -48,13 +48,18 @@ public class VirtualPropertyMakroResolver extends StrLookup { if ("now_ts".equals(rhs.toLowerCase())) { resolved = String.valueOf(Instant.now().toEpochMilli()); } else if ("overdue_ts".equals(rhs.toLowerCase())) { - resolved = String.valueOf(Instant.now().toEpochMilli() // - - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() // - - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis()); + resolved = String.valueOf(calculateOverdueTimestamp()); } return resolved; } + public long calculateOverdueTimestamp() { + long overdueTs = Instant.now().toEpochMilli() // + - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() // + - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis(); + return overdueTs; + } + private Duration getDurationForKey(TenantConfigurationKey key) { return DurationHelper.formattedStringToDuration(getRawStringForKey(key)); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java index 6571f8668..5503ae36e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java @@ -86,7 +86,7 @@ public final class TargetSpecifications { /** * {@link Specification} for retrieving {@link Target}s by "equal to given * {@link TargetUpdateStatus}". - * + * * @param updateStatus * to be filtered on * @param fetch @@ -110,10 +110,34 @@ public final class TargetSpecifications { }; } + /** + * {@link Specification} for retrieving {@link Target}s that are overdue. A + * target is overdue if it did not respond during the configured + * intervals:
+ * poll_itvl + overdue_itvl + * + * @param overdueTimestamp + * the calculated timestamp to compare with the last respond of a + * target (lastTargetQuery).
+ * The overdueTimestamp has to be calculated with + * the following expression:
+ * overdueTimestamp = nowTimestamp - poll_itvl - + * overdue_itvl + * + * @return the {@link Target} {@link Specification} + */ + public static Specification isOverdue(final long overdueTimestamp) { + return (targetRoot, query, cb) -> { + final Join targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo); + return cb.lessThanOrEqualTo( + targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery), overdueTimestamp); + }; + } + /** * {@link Specification} for retrieving {@link Target}s by * "like controllerId or like description or like ip address". - * + * * @param searchText * to be filtered on * @return the {@link Target} {@link Specification} @@ -129,7 +153,7 @@ public final class TargetSpecifications { /** * {@link Specification} for retrieving {@link Target}s by * "like controllerId". - * + * * @param distributionId * to be filtered on * @return the {@link Target} {@link Specification} @@ -166,7 +190,7 @@ public final class TargetSpecifications { /** * {@link Specification} for retrieving {@link Target}s by * "has no tag names"or "has at least on of the given tag names". - * + * * @param tagNames * to be filtered on * @param selectTargetWithNoTag @@ -199,7 +223,7 @@ public final class TargetSpecifications { /** * {@link Specification} for retrieving {@link Target}s by assigned * distribution set. - * + * * @param distributionSetId * the ID of the distribution set which must be assigned * @return the {@link Target} {@link Specification} @@ -213,7 +237,7 @@ public final class TargetSpecifications { /** * {@link Specification} for retrieving {@link Target}s by assigned * distribution set. - * + * * @param distributionSetId * the ID of the distribution set which must be assigned * @return the {@link Target} {@link Specification} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java index 1e8f102c7..e4c6a15b9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java @@ -10,20 +10,27 @@ package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.stream.Collector; import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.eclipse.hawkbit.ControllerPollProperties; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; @@ -32,6 +39,7 @@ import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Slice; import com.google.common.collect.Lists; @@ -60,26 +68,42 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final DistributionSet installedSet = testdataFactory.createDistributionSet("another"); + final Long lastTargetQueryNotOverdue = Instant.now().toEpochMilli(); + final Long lastTargetQueryAlwaysOverdue = 0L; + final Long lastTargetNull = null; + final String targetDsAIdPref = "targ-A"; - List targAs = targetManagement.createTargets( - testdataFactory.generateTargets(100, targetDsAIdPref, targetDsAIdPref.concat(" description"))); + List targAs = new ArrayList(); + for (Target t : testdataFactory.generateTargets(100, targetDsAIdPref, targetDsAIdPref.concat(" description"))) { + targAs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetQueryNotOverdue, + t.getTargetInfo().getAddress())); + } targAs = targetManagement.toggleTagAssignment(targAs, targTagX).getAssignedEntity(); final String targetDsBIdPref = "targ-B"; - List targBs = targetManagement.createTargets( - testdataFactory.generateTargets(100, targetDsBIdPref, targetDsBIdPref.concat(" description"))); + List targBs = new ArrayList(); + for (Target t : testdataFactory.generateTargets(100, targetDsBIdPref, targetDsBIdPref.concat(" description"))) { + targBs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetQueryAlwaysOverdue, + t.getTargetInfo().getAddress())); + } targBs = targetManagement.toggleTagAssignment(targBs, targTagY).getAssignedEntity(); targBs = targetManagement.toggleTagAssignment(targBs, targTagW).getAssignedEntity(); final String targetDsCIdPref = "targ-C"; - List targCs = targetManagement.createTargets( - testdataFactory.generateTargets(100, targetDsCIdPref, targetDsCIdPref.concat(" description"))); + List targCs = new ArrayList(); + for (Target t : testdataFactory.generateTargets(100, targetDsCIdPref, targetDsCIdPref.concat(" description"))) { + targCs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetQueryAlwaysOverdue, + t.getTargetInfo().getAddress())); + } targCs = targetManagement.toggleTagAssignment(targCs, targTagZ).getAssignedEntity(); targCs = targetManagement.toggleTagAssignment(targCs, targTagW).getAssignedEntity(); final String targetDsDIdPref = "targ-D"; - final List targDs = targetManagement.createTargets( - testdataFactory.generateTargets(100, targetDsDIdPref, targetDsDIdPref.concat(" description"))); + List targDs = new ArrayList(); + for (Target t : testdataFactory.generateTargets(100, targetDsDIdPref, targetDsDIdPref.concat(" description"))) { + targDs.add(targetManagement.createTarget(t, TargetUpdateStatus.UNKNOWN, lastTargetNull, + t.getTargetInfo().getAddress())); + } final String assignedC = targCs.iterator().next().getControllerId(); deploymentManagement.assignDistributionSet(setA.getId(), assignedC); @@ -155,6 +179,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { verifyThat200targetsWithGivenTagAreInStatusPendingorUnknown(targTagW, both, concat(targBs, targCs)); verfiyThat1TargetAIsInStatusPendingAndHasDSInstalled(installedSet, pending, targetManagement.findTargetByControllerID(installedC)); + + expected = concat(targBs, targCs); + expected.removeAll(targetManagement.findTargetByControllerID(Lists.newArrayList(assignedB, assignedC))); + verifyThat198TargetsAreInStatusUnknownAndOverdue(unknown, expected); } @Step @@ -164,10 +192,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "updatestatus==pending and installedds.name==" + installedSet.getName(); assertThat(targetManagement - .findTargetByFilters(pageReq, pending, null, installedSet.getId(), Boolean.FALSE, new String[0]) + .findTargetByFilters(pageReq, pending, null, null, installedSet.getId(), Boolean.FALSE, new String[0]) .getContent()).as("has number of elements").hasSize(1) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, installedSet.getId(), Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsExactly(expected) .as("and filter query returns the same result") @@ -175,7 +203,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, installedSet.getId(), + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, installedSet.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1) .as("and contains the following elements").containsExactly(expectedIdName) .as("and NAMED filter query returns the same result").containsAll(targetManagement @@ -190,10 +218,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "(updatestatus==pending or updatestatus==unknown) and tag==" + targTagW.getName(); - assertThat(targetManagement.findTargetByFilters(pageReq, both, null, null, Boolean.FALSE, targTagW.getName()) - .getContent()).as("has number of elements").hasSize(200) - .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(both, null, null, + assertThat(targetManagement + .findTargetByFilters(pageReq, both, null, null, null, Boolean.FALSE, targTagW.getName()).getContent()) + .as("has number of elements").hasSize(200).as("that number is also returned by count query") + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(both, null, null, null, Boolean.FALSE, targTagW.getName()))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") @@ -201,7 +229,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, both, null, null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, both, null, null, null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(200).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -224,10 +252,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final List expectedIdNames = convertToIdNames(expected); final String query = "updatestatus==pending and tag==" + targTagW.getName(); - assertThat(targetManagement.findTargetByFilters(pageReq, pending, null, null, Boolean.FALSE, targTagW.getName()) + assertThat(targetManagement + .findTargetByFilters(pageReq, pending, null, null, null, Boolean.FALSE, targTagW.getName()) .getContent()).as("has number of elements").hasSize(2) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, null, Boolean.FALSE, targTagW.getName()))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") @@ -235,7 +264,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(2).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -250,18 +279,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { + setA.getName() + ") and tag==" + targTagW.getName(); assertThat(targetManagement - .findTargetByFilters(pageReq, pending, null, setA.getId(), Boolean.FALSE, targTagW.getName()) + .findTargetByFilters(pageReq, pending, null, null, setA.getId(), Boolean.FALSE, targTagW.getName()) .getContent()).as("has number of elements").hasSize(2) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, setA.getId(), - Boolean.FALSE, targTagW.getName()))) + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, + setA.getId(), Boolean.FALSE, targTagW.getName()))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(2).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -275,11 +304,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ") and (name==*targ-B* or description==*targ-B*) and tag==" + targTagW.getName(); - assertThat(targetManagement - .findTargetByFilters(pageReq, pending, "%targ-B%", setA.getId(), Boolean.FALSE, targTagW.getName()) - .getContent()).as("has number of elements").hasSize(1) + assertThat(targetManagement.findTargetByFilters(pageReq, pending, null, "%targ-B%", setA.getId(), Boolean.FALSE, + targTagW.getName()).getContent()).as("has number of elements").hasSize(1) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, "%targ-B%", + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, "%targ-B%", setA.getId(), Boolean.FALSE, targTagW.getName()))) .as("and contains the following elements").containsExactly(expected) .as("and filter query returns the same result") @@ -287,11 +315,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, "%targ-B%", setA.getId(), Boolean.FALSE, - targTagW.getName())).as("has number of elements").hasSize(1).as("and contains the following elements") - .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") - .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new JpaTargetFilterQuery("test", query))); + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, "%targ-B%", setA.getId(), + Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(1) + .as("and contains the following elements").containsExactly(expectedIdName) + .as("and NAMED filter query returns the same result").containsAll(targetManagement + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -302,10 +330,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { + setA.getName() + ") and (name==*targ-A* or description==*targ-A*)"; assertThat(targetManagement - .findTargetByFilters(pageReq, pending, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0]) + .findTargetByFilters(pageReq, pending, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0]) .getContent()).as("has number of elements").hasSize(1) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, "%targ-A%", + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsExactly(expected) .as("and filter query returns the same result") @@ -313,11 +341,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, "%targ-A%", setA.getId(), Boolean.FALSE, - new String[0])).as("has number of elements").hasSize(1).as("and contains the following elements") - .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") - .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new JpaTargetFilterQuery("test", query))); + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, "%targ-A%", setA.getId(), + Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1) + .as("and contains the following elements").containsExactly(expectedIdName) + .as("and NAMED filter query returns the same result").containsAll(targetManagement + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -328,17 +356,17 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { + setA.getName() + ")"; assertThat(targetManagement - .findTargetByFilters(pageReq, pending, null, setA.getId(), Boolean.FALSE, new String[0]).getContent()) - .as("has number of elements").hasSize(3).as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, setA.getId(), - Boolean.FALSE, new String[0]))) + .findTargetByFilters(pageReq, pending, null, null, setA.getId(), Boolean.FALSE, new String[0]) + .getContent()).as("has number of elements").hasSize(3).as("that number is also returned by count query") + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, + setA.getId(), Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, setA.getId(), Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -351,10 +379,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final List expectedIdNames = convertToIdNames(expected); final String query = "updatestatus==pending"; - assertThat(targetManagement.findTargetByFilters(pageReq, pending, null, null, Boolean.FALSE, new String[0]) - .getContent()).as("has number of elements").hasSize(3) - .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, + assertThat(targetManagement + .findTargetByFilters(pageReq, pending, null, null, null, Boolean.FALSE, new String[0]).getContent()) + .as("has number of elements").hasSize(3).as("that number is also returned by count query") + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(pending, null, null, null, Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") @@ -362,9 +390,8 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat( - targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, Boolean.FALSE, new String[0])) - .as("has number of elements").hasSize(3).as("and contains the following elements") + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, pending, null, null, null, Boolean.FALSE, + new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); @@ -378,18 +405,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { + targTagW.getName(); assertThat(targetManagement - .findTargetByFilters(pageReq, unknown, "%targ-B%", null, Boolean.FALSE, targTagW.getName()) + .findTargetByFilters(pageReq, unknown, null, "%targ-B%", null, Boolean.FALSE, targTagW.getName()) .getContent()).as("has number of elements").hasSize(99) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, "%targ-B%", null, - Boolean.FALSE, targTagW.getName()))) + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, "%targ-B%", + null, Boolean.FALSE, targTagW.getName()))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, "%targ-B%", null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, "%targ-B%", null, Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(99).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -403,17 +430,17 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "updatestatus==unknown and (name==*targ-A* or description==*targ-A*)"; assertThat(targetManagement - .findTargetByFilters(pageReq, unknown, "%targ-A%", null, Boolean.FALSE, new String[0]).getContent()) - .as("has number of elements").hasSize(99).as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, "%targ-A%", null, - Boolean.FALSE, new String[0]))) + .findTargetByFilters(pageReq, unknown, null, "%targ-A%", null, Boolean.FALSE, new String[0]) + .getContent()).as("has number of elements").hasSize(99) + .as("that number is also returned by count query").hasSize(Ints.saturatedCast(targetManagement + .countTargetByFilters(unknown, null, "%targ-A%", null, Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, "%targ-A%", null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, "%targ-A%", null, Boolean.FALSE, new String[0])).as("has number of elements").hasSize(99).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -427,16 +454,16 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { + setA.getName() + ")"; assertThat(targetManagement - .findTargetByFilters(pageReq, unknown, null, setA.getId(), Boolean.FALSE, new String[0]).getContent()) - .as("has number of elements").hasSize(0).as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, setA.getId(), - Boolean.FALSE, new String[0]))) + .findTargetByFilters(pageReq, unknown, null, null, setA.getId(), Boolean.FALSE, new String[0]) + .getContent()).as("has number of elements").hasSize(0).as("that number is also returned by count query") + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null, + setA.getId(), Boolean.FALSE, new String[0]))) .as("and filter query returns the same result") .hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size()) .as("and NAMED filter query returns the same result").hasSize(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, setA.getId(), Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(0) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); @@ -449,10 +476,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "updatestatus==unknown and (tag==" + targTagY.getName() + " or tag==" + targTagW.getName() + ")"; - assertThat(targetManagement.findTargetByFilters(pageReq, unknown, null, null, Boolean.FALSE, targTagY.getName(), - targTagW.getName()).getContent()).as("has number of elements").hasSize(198) + assertThat(targetManagement.findTargetByFilters(pageReq, unknown, null, null, null, Boolean.FALSE, + targTagY.getName(), targTagW.getName()).getContent()).as("has number of elements").hasSize(198) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null, + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null, null, Boolean.FALSE, targTagY.getName(), targTagW.getName()))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") @@ -460,7 +487,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, null, Boolean.FALSE, targTagY.getName(), targTagW.getName())).as("has number of elements").hasSize(198) .as("and contains the following elements").containsAll(expectedIdNames) .as("and NAMED filter query returns the same result").containsAll(targetManagement @@ -473,10 +500,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final List expectedIdNames = convertToIdNames(expected); final String query = "updatestatus==unknown"; - assertThat(targetManagement.findTargetByFilters(pageReq, unknown, null, null, Boolean.FALSE, new String[0]) - .getContent()).as("has number of elements").hasSize(397) - .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null, + assertThat(targetManagement + .findTargetByFilters(pageReq, unknown, null, null, null, Boolean.FALSE, new String[0]).getContent()) + .as("has number of elements").hasSize(397).as("that number is also returned by count query") + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, null, null, null, Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") @@ -484,9 +511,34 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat( - targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, Boolean.FALSE, new String[0])) - .as("has number of elements").hasSize(397).as("and contains the following elements") + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, null, null, null, Boolean.FALSE, + new String[0])).as("has number of elements").hasSize(397).as("and contains the following elements") + .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") + .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, + new JpaTargetFilterQuery("test", query))); + } + + @Step + private void verifyThat198TargetsAreInStatusUnknownAndOverdue(final List unknown, + final List expected) { + final List expectedIdNames = convertToIdNames(expected); + // be careful: simple filters are concatenated using AND-gating + final String query = "lastcontrollerrequestat=le=${overdue_ts};updatestatus==UNKNOWN"; + + assertThat(targetManagement + .findTargetByFilters(pageReq, unknown, Boolean.TRUE, null, null, Boolean.FALSE, new String[0]) + .getContent()).as("has number of elements").hasSize(198) + .as("that number is also returned by count query") + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(unknown, Boolean.TRUE, null, + null, Boolean.FALSE, new String[0]))) + .as("and contains the following elements").containsAll(expected) + .as("and filter query returns the same result") + .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) + .as("and NAMED filter query returns the same result").containsAll(targetManagement + .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); + + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, unknown, Boolean.TRUE, null, null, Boolean.FALSE, + new String[0])).as("has number of elements").hasSize(198).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); @@ -499,10 +551,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { + " or installedds.name==" + setA.getName() + ")"; assertThat(targetManagement - .findTargetByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0]) + .findTargetByFilters(pageReq, null, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0]) .getContent()).as("has number of elements").hasSize(1) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-A%", + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-A%", setA.getId(), Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsExactly(expected) .as("and filter query returns the same result") @@ -510,11 +562,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, - new String[0])).as("has number of elements").hasSize(1).as("and contains the following elements") - .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") - .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new JpaTargetFilterQuery("test", query))); + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-A%", setA.getId(), + Boolean.FALSE, new String[0])).as("has number of elements").hasSize(1) + .as("and contains the following elements").containsExactly(expectedIdName) + .as("and NAMED filter query returns the same result").containsAll(targetManagement + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -522,18 +574,19 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final List expectedIdNames = convertToIdNames(expected); final String query = "assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName(); - assertThat(targetManagement.findTargetByFilters(pageReq, null, null, setA.getId(), Boolean.FALSE, new String[0]) + assertThat(targetManagement + .findTargetByFilters(pageReq, null, null, null, setA.getId(), Boolean.FALSE, new String[0]) .getContent()).as("has number of elements").hasSize(3) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, setA.getId(), - Boolean.FALSE, new String[0]))) + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, null, + setA.getId(), Boolean.FALSE, new String[0]))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") .containsAll(targetManagement.findTargetsAll(query, pageReq).getContent()) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, setA.getId(), Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, null, setA.getId(), Boolean.FALSE, new String[0])).as("has number of elements").hasSize(3).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -545,18 +598,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "(name==*targ-C* or description==*targ-C*) and tag==" + targTagX.getName() + " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")"; assertThat(targetManagement - .findTargetByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagX.getName()) + .findTargetByFilters(pageReq, null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagX.getName()) .getContent()).as("has number of elements").hasSize(0) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-C%", + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagX.getName()))) .as("and filter query returns the same result") .hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size()) .as("and NAMED filter query returns the same result").hasSize(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, - targTagX.getName())).as("has number of elements").hasSize(0) + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-C%", setA.getId(), + Boolean.FALSE, targTagX.getName())).as("has number of elements").hasSize(0) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @@ -566,18 +619,18 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "(name==*targ-A* or description==*targ-A*) and tag==" + targTagW.getName() + " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")"; assertThat(targetManagement - .findTargetByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, targTagW.getName()) + .findTargetByFilters(pageReq, null, null, "%targ-A%", setA.getId(), Boolean.FALSE, targTagW.getName()) .getContent()).as("has number of elements").hasSize(0) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-A%", + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-A%", setA.getId(), Boolean.FALSE, targTagW.getName()))) .as("and filter query returns the same result") .hasSize(targetManagement.findTargetsAll(query, pageReq).getContent().size()) .as("and NAMED filter query returns the same result").hasSize(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent().size()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-A%", setA.getId(), Boolean.FALSE, - targTagW.getName())).as("has number of elements").hasSize(0) + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-A%", setA.getId(), + Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(0) .as("and NAMED filter query returns the same result").containsAll(targetManagement .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @@ -589,10 +642,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final String query = "(name==*targ-c* or description==*targ-C*) and tag==" + targTagW.getName() + " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")"; assertThat(targetManagement - .findTargetByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagW.getName()) + .findTargetByFilters(pageReq, null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagW.getName()) .getContent()).as("has number of elements").hasSize(1) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-C%", + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagW.getName()))) .as("and contains the following elements").containsExactly(expected) .as("and filter query returns the same result") @@ -600,11 +653,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-C%", setA.getId(), Boolean.FALSE, - targTagW.getName())).as("has number of elements").hasSize(1).as("and contains the following elements") - .containsExactly(expectedIdName).as("and NAMED filter query returns the same result") - .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, - new JpaTargetFilterQuery("test", query))); + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-C%", setA.getId(), + Boolean.FALSE, targTagW.getName())).as("has number of elements").hasSize(1) + .as("and contains the following elements").containsExactly(expectedIdName) + .as("and NAMED filter query returns the same result").containsAll(targetManagement + .findAllTargetIdsByTargetFilterQuery(pageReq, new JpaTargetFilterQuery("test", query))); } @Step @@ -613,10 +666,10 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { final List expectedIdNames = convertToIdNames(expected); final String query = "(name==*targ-B* or description==*targ-B*) and (tag==" + targTagY.getName() + " or tag==" + targTagW.getName() + ")"; - assertThat(targetManagement.findTargetByFilters(pageReq, null, "%targ-B%", null, Boolean.FALSE, + assertThat(targetManagement.findTargetByFilters(pageReq, null, null, "%targ-B%", null, Boolean.FALSE, targTagY.getName(), targTagW.getName()).getContent()).as("has number of elements").hasSize(100) .as("that number is also returned by count query") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, "%targ-B%", null, + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, "%targ-B%", null, Boolean.FALSE, targTagY.getName(), targTagW.getName()))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") @@ -624,7 +677,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, "%targ-B%", null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, "%targ-B%", null, Boolean.FALSE, targTagY.getName(), targTagW.getName())).as("has number of elements").hasSize(100) .as("and contains the following elements").containsAll(expectedIdNames) .as("and NAMED filter query returns the same result").containsAll(targetManagement @@ -643,10 +696,11 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { private void verifyThat200TargetsHaveTagD(final TargetTag targTagD, final List expected) { final List expectedIdNames = convertToIdNames(expected); final String query = "tag==" + targTagD.getName(); - assertThat(targetManagement.findTargetByFilters(pageReq, null, null, null, Boolean.FALSE, targTagD.getName()) - .getContent()).as("Expected number of results is").hasSize(200) + assertThat(targetManagement + .findTargetByFilters(pageReq, null, null, null, null, Boolean.FALSE, targTagD.getName()).getContent()) + .as("Expected number of results is").hasSize(200) .as("and is expected number of results is equal to ") - .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, null, + .hasSize(Ints.saturatedCast(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, targTagD.getName()))) .as("and contains the following elements").containsAll(expected) .as("and filter query returns the same result") @@ -654,7 +708,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { .as("and NAMED filter query returns the same result").containsAll(targetManagement .findTargetsAll(new JpaTargetFilterQuery("test", query), pageReq).getContent()); - assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, null, Boolean.FALSE, + assertThat(targetManagement.findAllTargetIdsByFilters(pageReq, null, null, null, null, Boolean.FALSE, targTagD.getName())).as("has number of elements").hasSize(200).as("and contains the following elements") .containsAll(expectedIdNames).as("and NAMED filter query returns the same result") .containsAll(targetManagement.findAllTargetIdsByTargetFilterQuery(pageReq, @@ -664,12 +718,13 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { @Step private void verifyThatRepositoryContains400Targets() { - assertThat(targetManagement.findTargetByFilters(pageReq, null, null, null, null, new String[0]).getContent()) - .as("Overall we expect that many targets in the repository").hasSize(400) - .as("which is also reflected by repository count") - .hasSize(Ints.saturatedCast(targetManagement.countTargetsAll())) - .as("which is also reflected by call without specification") - .containsAll(targetManagement.findTargetsAll(pageReq).getContent()); + assertThat( + targetManagement.findTargetByFilters(pageReq, null, null, null, null, null, new String[0]).getContent()) + .as("Overall we expect that many targets in the repository").hasSize(400) + .as("which is also reflected by repository count") + .hasSize(Ints.saturatedCast(targetManagement.countTargetsAll())) + .as("which is also reflected by call without specification") + .containsAll(targetManagement.findTargetsAll(pageReq).getContent()); } @@ -691,7 +746,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { targInstalled = sendUpdateActionStatusToTargets(ds, targInstalled, Status.FINISHED, "installed"); final Slice result = targetManagement.findTargetsAllOrderByLinkedDistributionSet(pageReq, ds.getId(), - null, null, null, Boolean.FALSE, new String[0]); + null, null, null, null, Boolean.FALSE, new String[0]); final Comparator byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId()); @@ -708,6 +763,64 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { } + @Test + @Description("Tests the correct order of targets with applied overdue filter based on selected distribution set. The system expects to have an order based on installed, assigned DS.") + public void targetSearchWithOverdueFilterAndOrderByDistributionSet() { + + final Long lastTargetQueryAlwaysOverdue = 0L; + final Long lastTargetQueryNotOverdue = Instant.now().toEpochMilli(); + final Long lastTargetNull = null; + + final Long[] overdueMix = { lastTargetQueryAlwaysOverdue, lastTargetQueryNotOverdue, + lastTargetQueryAlwaysOverdue, lastTargetNull, lastTargetQueryAlwaysOverdue }; + + List notAssignedToBeCreated = testdataFactory.generateTargets(overdueMix.length, "not", + "first description"); + List targAssignedToBeCreated = testdataFactory.generateTargets(overdueMix.length, "assigned", + "first description"); + List targInstalledToBeCreated = testdataFactory.generateTargets(overdueMix.length, "installed", + "first description"); + + List notAssigned = new ArrayList<>(); + List targAssigned = new ArrayList<>(); + List targInstalled = new ArrayList<>(); + + for (int i = 0; i < overdueMix.length; i++) { + notAssigned.add(targetManagement.createTarget(notAssignedToBeCreated.get(i), TargetUpdateStatus.UNKNOWN, + overdueMix[i], notAssignedToBeCreated.get(i).getTargetInfo().getAddress())); + targAssigned.add(targetManagement.createTarget(targAssignedToBeCreated.get(i), TargetUpdateStatus.UNKNOWN, + overdueMix[i], targAssignedToBeCreated.get(i).getTargetInfo().getAddress())); + targInstalled.add(targetManagement.createTarget(targInstalledToBeCreated.get(i), TargetUpdateStatus.UNKNOWN, + overdueMix[i], targInstalledToBeCreated.get(i).getTargetInfo().getAddress())); + } + + final DistributionSet ds = testdataFactory.createDistributionSet("a"); + + targAssigned = deploymentManagement.assignDistributionSet(ds, targAssigned).getAssignedEntity(); + targInstalled = deploymentManagement.assignDistributionSet(ds, targInstalled).getAssignedEntity(); + targInstalled = sendUpdateActionStatusToTargets(ds, targInstalled, Status.FINISHED, "installed"); + + final Slice result = targetManagement.findTargetsAllOrderByLinkedDistributionSet(pageReq, ds.getId(), + null, null, Boolean.TRUE, null, Boolean.FALSE, new String[0]); + + final Comparator byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId()); + + assertThat(result.getNumberOfElements()).isEqualTo(9); + final List expected = new ArrayList<>(); + expected.addAll(targInstalled.stream().sorted(byId) + .filter(item -> lastTargetQueryAlwaysOverdue.equals(item.getTargetInfo().getLastTargetQuery())) + .collect(Collectors.toList())); + expected.addAll(targAssigned.stream().sorted(byId) + .filter(item -> lastTargetQueryAlwaysOverdue.equals(item.getTargetInfo().getLastTargetQuery())) + .collect(Collectors.toList())); + expected.addAll(notAssigned.stream().sorted(byId) + .filter(item -> lastTargetQueryAlwaysOverdue.equals(item.getTargetInfo().getLastTargetQuery())) + .collect(Collectors.toList())); + + assertThat(result.getContent()).containsExactly(expected.toArray(new Target[0])); + + } + @Test @Description("Verfies that targets with given assigned DS are returned from repository.") public void findTargetByAssignedDistributionSet() { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java index 06f853db6..b71266aa4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java @@ -599,7 +599,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { targetManagement.toggleTagAssignment(tagABCTargets, tagB); targetManagement.toggleTagAssignment(tagABCTargets, tagC); - assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "X")) + assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "X")) .as("Target count is wrong").isEqualTo(0); // search for targets with tag tagA @@ -629,11 +629,11 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { checkTargetHasNotTags(tagCTargets, tagA, tagB); // check again target lists refreshed from DB - assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "A")) + assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "A")) .as("Target count is wrong").isEqualTo(targetWithTagA.size()); - assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "B")) + assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "B")) .as("Target count is wrong").isEqualTo(targetWithTagB.size()); - assertThat(targetManagement.countTargetByFilters(null, null, null, Boolean.FALSE, "C")) + assertThat(targetManagement.countTargetByFilters(null, null, null, null, Boolean.FALSE, "C")) .as("Target count is wrong").isEqualTo(targetWithTagC.size()); } @@ -750,7 +750,8 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { final String[] tagNames = null; final List targetsListWithNoTag = targetManagement - .findTargetByFilters(new PageRequest(0, 500), null, null, null, Boolean.TRUE, tagNames).getContent(); + .findTargetByFilters(new PageRequest(0, 500), null, null, null, null, Boolean.TRUE, tagNames) + .getContent(); assertThat(50).as("Total targets").isEqualTo(targetManagement.findAllTargetIds().size()); assertThat(25).as("Targets with no tag").isEqualTo(targetsListWithNoTag.size()); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java index 2a860c9b8..c3c6e9294 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java @@ -370,7 +370,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable 0) { + if (targetManagement.countTargetByFilters(null, null, null, ds.getId(), Boolean.FALSE, new String[] {}) > 0) { /* Distribution is already assigned */ notification.displayValidationError(i18n.get("message.dist.inuse", HawkbitCommonUtil.concatStrings(":", ds.getName(), ds.getVersion()))); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java index 4874bd960..2c6c83e8a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java @@ -14,5 +14,22 @@ package org.eclipse.hawkbit.ui.management.event; * */ public enum ManagementUIEvent { - SHOW_COUNT_MESSAGE, UPDATE_COUNT, UPDATE_FILTERCOUNT_MESSAGE, HIDE_TARGET_TAG_LAYOUT, SHOW_TARGET_TAG_LAYOUT, HIDE_DISTRIBUTION_TAG_LAYOUT, SHOW_DISTRIBUTION_TAG_LAYOUT, MAX_ACTION_HISTORY, MIN_ACTION_HISTORY, CLOSE_SAVE_ACTIONS_WINDOW, UNASSIGN_TARGET_TAG, UNASSIGN_DISTRIBUTION_TAG, ASSIGN_TARGET_TAG, ASSIGN_DISTRIBUTION_TAG, TARGET_TABLE_FILTER, RESET_SIMPLE_FILTERS, RESET_TARGET_FILTER_QUERY + SHOW_COUNT_MESSAGE, // + UPDATE_COUNT, // + UPDATE_FILTERCOUNT_MESSAGE, // + HIDE_TARGET_TAG_LAYOUT, // + SHOW_TARGET_TAG_LAYOUT, // + HIDE_DISTRIBUTION_TAG_LAYOUT, // + SHOW_DISTRIBUTION_TAG_LAYOUT, // + MAX_ACTION_HISTORY, // + MIN_ACTION_HISTORY, // + CLOSE_SAVE_ACTIONS_WINDOW, // + UNASSIGN_TARGET_TAG, // + UNASSIGN_DISTRIBUTION_TAG, // + ASSIGN_TARGET_TAG, // + ASSIGN_DISTRIBUTION_TAG, // + TARGET_TABLE_FILTER, // + RESET_SIMPLE_FILTERS, // + RESET_TARGET_FILTER_QUERY + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java index 1c1d14d94..834f06031 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java @@ -14,5 +14,14 @@ package org.eclipse.hawkbit.ui.management.event; * */ public enum TargetFilterEvent { - FILTER_BY_TEXT, FILTER_BY_TAG, REMOVE_FILTER_BY_TEXT, REMOVE_FILTER_BY_TAG, FILTER_BY_STATUS, FILTER_BY_DISTRIBUTION, REMOVE_FILTER_BY_STATUS, REMOVE_FILTER_BY_DISTRIBUTION, FILTER_BY_TARGET_FILTER_QUERY, REMOVE_FILTER_BY_TARGET_FILTER_QUERY + FILTER_BY_TEXT, // + FILTER_BY_TAG, // + REMOVE_FILTER_BY_TEXT, // + REMOVE_FILTER_BY_TAG, // + FILTER_BY_STATUS, // + FILTER_BY_DISTRIBUTION, // + REMOVE_FILTER_BY_STATUS, // + REMOVE_FILTER_BY_DISTRIBUTION, // + FILTER_BY_TARGET_FILTER_QUERY, // + REMOVE_FILTER_BY_TARGET_FILTER_QUERY } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java index 70ed995a6..60aa78abc 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java @@ -143,6 +143,7 @@ public class CountMessageLabel extends Label { } message.append(HawkbitCommonUtil.SP_STRING_SPACE); final String status = i18n.get("label.filter.status"); + final String overdue = i18n.get("label.filter.overdue"); final String tags = i18n.get("label.filter.tags"); final String text = i18n.get("label.filter.text"); final String dists = i18n.get("label.filter.dist"); @@ -150,6 +151,7 @@ public class CountMessageLabel extends Label { final StringBuilder filterMesgBuf = new StringBuilder(i18n.get("label.filter")); filterMesgBuf.append(HawkbitCommonUtil.SP_STRING_SPACE); filterMesgBuf.append(getStatusMsg(targFilParams.getClickedStatusTargetTags(), status)); + filterMesgBuf.append(getOverdueStateMsg(targFilParams.isOverdueFilterEnabled(), overdue)); filterMesgBuf .append(getTagsMsg(targFilParams.isNoTagSelected(), targFilParams.getClickedTargetTags(), tags)); filterMesgBuf.append(getSerachMsg( @@ -230,6 +232,17 @@ public class CountMessageLabel extends Label { return status.isEmpty() ? HawkbitCommonUtil.SP_STRING_SPACE : param; } + /** + * Get Overdue State Message. + * + * @param overdueState + * as flag + * @return String as msg. + */ + private static String getOverdueStateMsg(final boolean overdueState, final String param) { + return !overdueState ? HawkbitCommonUtil.SP_STRING_SPACE : param; + } + /** * Get Tags Message. * diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/TargetTableFilters.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/TargetTableFilters.java index 289927660..92dd627ae 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/TargetTableFilters.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/TargetTableFilters.java @@ -31,6 +31,8 @@ public class TargetTableFilters implements Serializable { private final List clickedTargetTags = new ArrayList<>(); private final List clickedStatusTargetTags = new ArrayList<>(); + private boolean isOverdueFilterEnabled = Boolean.FALSE; + private String searchText; private DistributionSetIdName distributionSet; private Long pinnedDistId; @@ -130,7 +132,8 @@ public class TargetTableFilters implements Serializable { * {@code false} */ public boolean hasFilter() { - return isFilteredByTextOrDs() || hasTagsSelected() || isFilteredByStatusOrCustomFilter(); + return isFilteredByTextOrDs() || hasTagsSelected() || isFilteredByStatusOrCustomFilter() + || isOverdueFilterEnabled(); } private boolean hasTagsSelected() { @@ -160,4 +163,12 @@ public class TargetTableFilters implements Serializable { this.targetFilterQuery = targetFilterQuery; } + public boolean isOverdueFilterEnabled() { + return isOverdueFilterEnabled; + } + + public void setOverdueFilterEnabled(boolean isOverdueFilterEnabled) { + this.isOverdueFilterEnabled = isOverdueFilterEnabled; + } + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index 079544e63..6459935ab 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -51,6 +51,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { private Sort sort = new Sort(TARGET_TABLE_CREATE_AT_SORT_ORDER, "createdAt"); private transient Collection status = null; + private transient Boolean overdueState = null; private String[] targetTags = null; private Long distributionId = null; private String searchText = null; @@ -80,6 +81,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { if (isNotNullOrEmpty(queryConfig)) { status = (Collection) queryConfig.get(SPUIDefinitions.FILTER_BY_STATUS); + overdueState = (Boolean) queryConfig.get(SPUIDefinitions.FILTER_BY_OVERDUE_STATE); targetTags = (String[]) queryConfig.get(SPUIDefinitions.FILTER_BY_TAG); noTagClicked = (Boolean) queryConfig.get(SPUIDefinitions.FILTER_BY_NO_TAG); distributionId = (Long) queryConfig.get(SPUIDefinitions.FILTER_BY_DISTRIBUTION); @@ -113,7 +115,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { if (pinnedDistId != null) { targetBeans = getTargetManagement().findTargetsAllOrderByLinkedDistributionSet( new OffsetBasedPageRequest(startIndex, SPUIDefinitions.PAGE_SIZE, sort), pinnedDistId, - distributionId, status, searchText, noTagClicked, targetTags); + distributionId, status, overdueState, searchText, noTagClicked, targetTags); } else if (null != targetFilterQuery) { targetBeans = getTargetManagement().findTargetsAll(targetFilterQuery, new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort)); @@ -123,7 +125,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { } else { targetBeans = getTargetManagement().findTargetByFilters( new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort), status, - searchText, distributionId, noTagClicked, targetTags); + overdueState, searchText, distributionId, noTagClicked, targetTags); } for (final Target targ : targetBeans) { final ProxyTarget prxyTarget = new ProxyTarget(); @@ -169,6 +171,13 @@ public class TargetBeanQuery extends AbstractBeanQuery { return true; } + private Boolean isOverdueFilterEnabled() { + if (Boolean.TRUE.equals(overdueState)) { + return Boolean.TRUE; + } + return Boolean.FALSE; + } + @Override protected void saveBeans(final List addedTargets, final List modifiedTargets, final List removedTargets) { @@ -176,7 +185,8 @@ public class TargetBeanQuery extends AbstractBeanQuery { } private Boolean anyFilterSelected() { - if (status == null && distributionId == null && Strings.isNullOrEmpty(searchText) && !isTagSelected()) { + if (status == null && distributionId == null && Strings.isNullOrEmpty(searchText) && !isTagSelected() + && !isOverdueFilterEnabled()) { return false; } return true; @@ -191,8 +201,8 @@ public class TargetBeanQuery extends AbstractBeanQuery { } else if (!anyFilterSelected()) { size = totSize; } else { - size = getTargetManagement().countTargetByFilters(status, searchText, distributionId, noTagClicked, - targetTags); + size = getTargetManagement().countTargetByFilters(status, overdueState, searchText, distributionId, + noTagClicked, targetTags); } final ManagementUIState tmpManagementUIState = getManagementUIState(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java index cc4ad98bc..9773f2adb 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java @@ -369,6 +369,9 @@ public class TargetTable extends AbstractTable { .getClickedStatusTargetTags(); queryConfig.put(SPUIDefinitions.FILTER_BY_STATUS, statusList); } + if (managementUIState.getTargetTableFilters().isOverdueFilterEnabled()) { + queryConfig.put(SPUIDefinitions.FILTER_BY_OVERDUE_STATE, Boolean.TRUE); + } return queryConfig; } @@ -873,6 +876,7 @@ public class TargetTable extends AbstractTable { managementUIState.setTargetsCountAll(totalTargetsCount); Collection status = null; + Boolean overdueState = null; String[] targetTags = null; Long distributionId = null; String searchText = null; @@ -884,6 +888,9 @@ public class TargetTable extends AbstractTable { if (isFilteredByStatus()) { status = managementUIState.getTargetTableFilters().getClickedStatusTargetTags(); } + if (managementUIState.getTargetTableFilters().isOverdueFilterEnabled()) { + overdueState = managementUIState.getTargetTableFilters().isOverdueFilterEnabled(); + } if (managementUIState.getTargetTableFilters().getDistributionSet().isPresent()) { distributionId = managementUIState.getTargetTableFilters().getDistributionSet().get().getId(); } @@ -895,8 +902,8 @@ public class TargetTable extends AbstractTable { pinnedDistId = managementUIState.getTargetTableFilters().getPinnedDistId().get(); } - final long size = getTargetsCountWithFilter(totalTargetsCount, status, targetTags, distributionId, searchText, - noTagClicked, pinnedDistId); + final long size = getTargetsCountWithFilter(totalTargetsCount, status, overdueState, targetTags, distributionId, + searchText, noTagClicked, pinnedDistId); if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { managementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); @@ -904,8 +911,8 @@ public class TargetTable extends AbstractTable { } private long getTargetsCountWithFilter(final long totalTargetsCount, final Collection status, - final String[] targetTags, final Long distributionId, final String searchText, final Boolean noTagClicked, - final Long pinnedDistId) { + final Boolean overdueState, final String[] targetTags, final Long distributionId, final String searchText, + final Boolean noTagClicked, final Long pinnedDistId) { final long size; if (managementUIState.getTargetTableFilters().getTargetFilterQuery().isPresent()) { size = targetManagement.countTargetByTargetFilterQuery( @@ -913,7 +920,8 @@ public class TargetTable extends AbstractTable { } else if (!anyFilterSelected(status, pinnedDistId, noTagClicked, targetTags, searchText)) { size = totalTargetsCount; } else { - size = targetManagement.countTargetByFilters(status, searchText, distributionId, noTagClicked, targetTags); + size = targetManagement.countTargetByFilters(status, overdueState, searchText, distributionId, noTagClicked, + targetTags); } return size; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java index d2be86aa1..b393e1ff1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java @@ -54,16 +54,20 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click @Autowired private ManagementUIState managementUIState; + private static final String overdueCaption = "overdue"; + private Button unknown; private Button inSync; private Button pending; private Button error; private Button registered; + private Button overdue; private Boolean unknownBtnClicked = false; private Boolean errorBtnClicked = false; private Boolean pendingBtnClicked = false; private Boolean inSyncBtnClicked = false; private Boolean registeredBtnClicked = false; + private Boolean overdueBtnClicked = false; private Button buttonClicked; private static final String BTN_CLICKED = "btnClicked"; @@ -105,6 +109,15 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click addComponent(buttonLayout); setComponentAlignment(buttonLayout, Alignment.MIDDLE_CENTER); + final HorizontalLayout overdueLayout = new HorizontalLayout(); + final Label overdueLabel = new LabelBuilder().name(i18n.get("label.filter.by.overdue")).buildLabel(); + overdueLayout.setStyleName("overdue-button-layout"); + overdueLayout.addComponent(overdue); + overdueLayout.setComponentAlignment(overdue, Alignment.MIDDLE_LEFT); + overdueLayout.addComponent(overdueLabel); + overdueLayout.setComponentAlignment(overdueLabel, Alignment.MIDDLE_LEFT); + addComponent(overdueLayout); + } private void restorePreviousState() { @@ -129,6 +142,10 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click } } } + if (managementUIState.getTargetTableFilters().isOverdueFilterEnabled()) { + overdue.addStyleName(BTN_CLICKED); + overdueBtnClicked = Boolean.TRUE; + } } /** @@ -150,18 +167,23 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click registered = SPUIComponentProvider.getButton(UIComponentIdProvider.REGISTERED_STATUS_ICON, TargetUpdateStatus.REGISTERED.toString(), i18n.get("tooltip.status.registered"), SPUIButtonDefinitions.SP_BUTTON_STATUS_STYLE, false, FontAwesome.SQUARE, SPUIButtonStyleSmall.class); + overdue = SPUIComponentProvider.getButton(SPUIComponentIdProvider.OVERDUE_STATUS_ICON, + overdueCaption, i18n.get("tooltip.status.overdue"), + SPUIButtonDefinitions.SP_BUTTON_STATUS_STYLE, false, FontAwesome.SQUARE, SPUIButtonStyleSmall.class); applyStatusBtnStyle(); unknown.setData("filterStatusOne"); inSync.setData("filterStatusTwo"); pending.setData("filterStatusThree"); error.setData("filterStatusFour"); registered.setData("filterStatusFive"); + overdue.setData("filterStatusSix"); unknown.addClickListener(this); inSync.addClickListener(this); pending.addClickListener(this); error.addClickListener(this); registered.addClickListener(this); + overdue.addClickListener(this); } /** @@ -173,6 +195,7 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click pending.addStyleName("pendingBtn"); error.addStyleName("errorBtn"); registered.addStyleName("registeredBtn"); + overdue.addStyleName("overdueBtn"); } @Override @@ -188,6 +211,8 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click processErrorFilterStatus(); } else if (event.getButton().getCaption().equalsIgnoreCase(TargetUpdateStatus.REGISTERED.toString())) { processRegisteredFilterStatus(); + } else if (event.getButton().getCaption().equalsIgnoreCase(overdueCaption)) { + processOverdueFilterStatus(); } } @@ -231,9 +256,26 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click processCommonFilterStatus(TargetUpdateStatus.REGISTERED, registeredBtnClicked); } + /** + * Process - OVERDUE. + */ + private void processOverdueFilterStatus() { + overdueBtnClicked = !overdueBtnClicked; + managementUIState.getTargetTableFilters().setOverdueFilterEnabled(overdueBtnClicked); + + if (overdueBtnClicked) { + buttonClicked.addStyleName(BTN_CLICKED); + eventBus.publish(this, TargetFilterEvent.FILTER_BY_STATUS); + } else { + buttonClicked.removeStyleName(BTN_CLICKED); + eventBus.publish(this, TargetFilterEvent.REMOVE_FILTER_BY_STATUS); + } + + } + /** * Process - COMMON PROCESS. - * + * * @param status * as enum * @param buttonReset @@ -268,11 +310,12 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click inSync.removeStyleName(BTN_CLICKED); error.removeStyleName(BTN_CLICKED); pending.removeStyleName(BTN_CLICKED); + overdue.removeStyleName(BTN_CLICKED); } /** * Check if any status button in clicked. - * + * * @return */ private boolean isStatusFilterApplied() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java new file mode 100644 index 000000000..13d7ced1a --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java @@ -0,0 +1,846 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.utils; + +/** + * Interface to provide the unchanged constants. + * + * + * + * + * + */ +public final class SPUIComponentIdProvider { + /** + * ID-Target. + */ + public static final String TARGET_TABLE_ID = "target.tableId"; + /** + * ID- Targ.Cont ID. + */ + public static final String TARGET_ADD_CONTROLLER_ID = "target.add.ctrlId"; + /** + * ID-Targ.Name. + */ + public static final String TARGET_ADD_NAME = "target.add.name"; + /** + * ID-Targ.Disc. + */ + public static final String TARGET_ADD_DESC = "target.add.desc"; + /** + * ID-Targ.DEL. + */ + public static final String TARGET_DELETE_ALL = "target.delete.all"; + /** + * ID-SW.DEL. + */ + public static final String SW_DELETE_ALL = "swmodule.delete.all"; + /** + * ID-Targ.Edit.icon. + */ + public static final String TARGET_EDIT_ICON = "target.edit.icon"; + /** + * ID-Targ.PIN. + */ + public static final String TARGET_PIN_ICON = "target.pin.icon"; + + /** + * Target search text id. + */ + public static final String TARGET_TEXT_FIELD = "target.search.textfield"; + + /** + * ID for add target filter icon + */ + public static final String TARGET_FILTER_ADD_ICON_ID = "target.filter.add.id"; + + /** + * ID-Dist. + */ + public static final String DIST_TABLE_ID = "dist.tableId"; + /** + * ID-Dist.Name. + */ + public static final String DIST_ADD_NAME = "dist.add.name"; + /** + * ID-Dist.Version. + */ + public static final String DIST_ADD_VERSION = "dist.add.version"; + /** + * ID-Dist.DistSetType. + */ + public static final String DIST_ADD_DISTSETTYPE = "dist.add.distsettype"; + /** + * ID-Dist.desc. + */ + public static final String DIST_ADD_DESC = "dist.add.desc"; + /** + * /** ID-Dist.DELETE. + */ + public static final String DIST_DELETE_ALL = "dist.delete.all"; + /** + * ID-Dist.MigCheck. + */ + public static final String DIST_ADD_MIGRATION_CHECK = "dist.add.required.migration"; + /** + * ID-Dist.Search.icon. + */ + public static final String DIST_SEARCH_ICON = "dist.search.rest.icon"; + /** + * ID-Dist.Search.txt. + */ + public static final String DIST_SEARCH_TEXTFIELD = "dist.search.textfield"; + /** + * ID - Dist.Add. + */ + public static final String DIST_ADD_ICON = "dist.add.icon"; + /** + * ID for Distribution Tag ComboBox + */ + public static final String DIST_TAG_COMBO = "dist.tag.combo"; + /** + * ID-Dist.PIN. + */ + public static final String DIST_PIN_BUTTON = "dist.pin.button"; + /** + * ID - soft.module.name. + */ + public static final String SOFT_MODULE_NAME = "soft.module.name"; + /** + * ID - soft.module.version. + */ + public static final String SOFT_MODULE_VERSION = "soft.module.version"; + + /** + * ID - soft.module.vendor. + */ + public static final String SOFT_MODULE_VENDOR = "soft.module.vendor"; + + /** + * ID - Save Assign. + */ + public static final String SAVE_ASSIGNMENT = "save.actions.popup.assign"; + + /** + * ID - Discard Assign. + */ + public static final String DISCARD_ASSIGNMENT = "discard.actions.popup.assign"; + + /** + * ID - Delete Distribution SetType Save. + */ + public static final String SAVE_DELETE_DIST_SET_TYPE = "save.actions.popup.delete.dist.set.type"; + + /** + * ID - Discard Distribution SetType. + */ + public static final String DISCARD_DIST_SET_TYPE = "save.actions.popup.discard.dist.set.type"; + /** + * ID Delete Software Module Type save. + */ + public static final String SAVE_DELETE_SW_MODULE_TYPE = "save.actions.popup.delete.sw.module.type"; + + /** + * ID - Discard SW Module Type. + */ + public static final String DISCARD_SW_MODULE_TYPE = "save.actions.popup.discard.sw.module.type"; + + /** + * Action history table cancel Id. + */ + public static final String ACTION_DETAILS_SOFT_ID = "action.details.soft.group"; + + /** + * ID - Label. + */ + public static final String ACTION_LABEL = "save.actions.popup.actionMsg"; + /** + * ID - Count. + */ + public static final String COUNT_LABEL = "count.message.label"; + /** + * UNKNOWN_STATUS_ICON ID. + */ + public static final String UNKNOWN_STATUS_ICON = "unknown.status.icon"; + /** + * INSYNCH_STATUS_ICON ID. + */ + public static final String INSYNCH_STATUS_ICON = "insynch.status.icon"; + /** + * PENDING_STATUS_ICON ID. + */ + public static final String PENDING_STATUS_ICON = "pending.status.icon"; + /** + * ERROR_STATUS_ICON ID. + */ + public static final String ERROR_STATUS_ICON = "error.status.icon"; + /** + * REGISTERED_STATUS_ICON ID. + */ + public static final String REGISTERED_STATUS_ICON = "registered.status.icon"; + /** + * OVERDUE_STATUS_ICON ID. + */ + public static final String OVERDUE_STATUS_ICON = "overdue.status.icon"; + /** + * DROP filter icon id. + */ + public static final String TARGET_DROP_FILTER_ICON = "target.drop.filter.icon"; + + /** + * Pending action button id. + */ + public static final String PENDING_ACTION_BUTTON = "pending.action.button"; + /** + * Action history table Id. + */ + public static final String ACTION_HISTORY_TABLE_ID = "action.history.tableId"; + + /** + * Action history table cancel Id. + */ + public static final String ACTION_HISTORY_TABLE_CANCEL_ID = "action.history.table.action.cancel"; + + /** + * Action history table force Id. + */ + public static final String ACTION_HISTORY_TABLE_FORCE_ID = "action.history.table.action.force"; + + /** + * Action history table force quit Id. + */ + public static final String ACTION_HISTORY_TABLE_FORCE_QUIT_ID = "action.history.table.action.force.quit"; + + /** + * Target filter wrapper id. + */ + public static final String TARGET_FILTER_WRAPPER_ID = "target-drop-filter"; + + /** + * Delete button wrapper id. + */ + public static final String DELETE_BUTTON_WRAPPER_ID = "delete.button"; + /** + * tag color preview button id. + */ + public static final String TAG_COLOR_PREVIEW_ID = "tag.color.preview"; + /** + * Id for ColorPickerLayout + */ + public static final String COLOR_PICKER_LAYOUT = "color.picker.layout"; + /** + * Id for ColorPickerLayout's red slider + */ + public static final String COLOR_PICKER_RED_SLIDER = "color.picker.red.slider"; + /** + * Id for Color preview field with the color code + */ + public static final String COLOR_PREVIEW_FIELD = "color-preview-field"; + /** + * Id for OptionGroup Create/Update tag + */ + public static final String OPTION_GROUP = "create.update.tag"; + /** + * Confirmation dialogue OK button id. + */ + public static final String OK_BUTTON = "ok.button"; + /** + * Upload - type button id. + */ + public static final String UPLOAD_TYPE_BUTTON_PREFIX = "upload.type.button."; + /** + * Upload - process button id. + */ + public static final String UPLOAD_PROCESS_BUTTON = "upload.process.button"; + /** + * Upload - discard button id. + */ + public static final String UPLOAD_DISCARD_BUTTON = "upload.discard.button"; + + /** + * Upload - artifact detail close button. + */ + public static final String UPLOAD_ARTIFACT_DETAILS_CLOSE = "upload.artifactdetails.close.button"; + /** + * Upload - artifact detail table. + */ + public static final String UPLOAD_ARTIFACT_DETAILS_TABLE = "upload.artifactdetails.table"; + + /** + * Upload - artifact upload button. + */ + public static final String UPLOAD_BUTTON = "artifact.upload.button"; + /** + * Upload - process button id. + */ + public static final String UPLOAD_DISCARD_DETAILS_BUTTON = "upload.discard.details.button"; + /** + * Upload - delete button id. + */ + public static final String UPLOAD_DELETE_ICON = "upload.delete.button"; + + /** + * Upload- file delete button id. + */ + public static final String UPLOAD_FILE_DELETE_ICON = "upload.file.delete.button"; + /** + * ID-Dist. + */ + public static final String UPLOAD_SOFTWARE_MODULE_TABLE = "upload.swModule.table"; + + /** + * Upload result popup close button. + */ + public static final String UPLOAD_ARTIFACT_RESULT_POPUP_CLOSE = "upload.resultwindow.close.button"; + + /** + * Upload result popup close button. + */ + public static final String UPLOAD_ARTIFACT_RESULT_CLOSE = "upload.results.close.button"; + /** + * Upload - artifact result table. + */ + public static final String UPLOAD_RESULT_TABLE = "upload.result.table"; + /** + * Upload - software module search text id. + */ + public static final String SW_MODULE_SEARCH_TEXT_FIELD = "swmodule.search.textfield"; + /** + * Upload - software module search reset icon id. + */ + public static final String SW_MODULE_SEARCH_RESET_ICON = "sw.search.reset.icon"; + + /** + * Upload - artifact upload error reason. + */ + public static final String UPLOAD_ERROR_REASON = "upload-error-reason"; + + /** + * Upload - artifact upload - Software module add button. + */ + public static final String SW_MODULE_ADD_BUTTON = "sw.module.add.button"; + + /** + * Upload - artifact upload - Software module type combo id. + */ + public static final String SW_MODULE_TYPE = "sw.module.select.type"; + + /** + * Upload - artifact upload - Software module description. + */ + public static final String ADD_SW_MODULE_DESCRIPTION = "sw.module.description"; + + /** + * ID-Targ.Detail.icon. + */ + public static final String SW_TABLE_ATRTIFACT_DETAILS_ICON = "swmodule.artifact.details.icon"; + + /** + * Artifact upload - sw module edit button id. + */ + public static final String UPLOAD_SW_MODULE_EDIT_BUTTON = "swmodule.edit.button"; + + /** + * Ds edit button id. + */ + public static final String DS_EDIT_BUTTON = "ds.edit.button"; + /** + * Upload Artifact details max table Id. + */ + public static final String UPLOAD_ARTIFACT_DETAILS_TABLE_MAX = "upload.artifactdetails.table.max"; + + /** + * Target tag close button. + */ + public static final String HIDE_TARGET_TAGS = "hide.target.tags"; + + /** + * Show target tag layout icon. + */ + public static final String SHOW_TARGET_TAGS = "show.target.tags.icon"; + + /** + * ID-Target tag table. + */ + public static final String TARGET_TAG_TABLE_ID = "target.tag.tableId"; + /** + * ID-Distibution tag table. + */ + public static final String DISTRIBUTION_TAG_TABLE_ID = "distriution.tag.tableId"; + /** + * ID-Software module type table. + */ + public static final String SW_MODULE_TYPE_TABLE_ID = "sw.module.type.table"; + + /** + * ID-Target tag table. + */ + public static final String DISTRIBUTION_SET_TYPE_TABLE_ID = "dist.set.type.tableId"; + + /** + * Tab sheet id. + */ + public static final String TARGET_DETAILS_TABSHEET = "target.details.tabsheet"; + /** + * Tab sheet id. + */ + public static final String DISTRIBUTION_DETAILS_TABSHEET = "distribution.details.tabsheet."; + + /** + * Combobox id. + */ + public static final String SYSTEM_CONFIGURATION_DEFAULTDIS_COMBOBOX = "default.disset.combobox"; + + /** + * Button save id. + */ + public static final String SYSTEM_CONFIGURATION_SAVE = "system.configuration.save"; + + /** + * ID for save button in pop-up-windows instance of commonDialogWindow + */ + public static final String SAVE_BUTTON = "common.dialog.window.save"; + + /** + * ID for cancel button in pop-up-windows instance of commonDialogWindow + */ + public static final String CANCEL_BUTTON = "common.dialog.window.cancel"; + + /** + * Cancel button is. + */ + public static final String SYSTEM_CONFIGURATION_CANCEL = "system.configuration.cancel"; + + /** + * Id of maximize/minimize icon of table - Software module table. + */ + public static final String SW_MAX_MIN_TABLE_ICON = "sw.max.min.table.icon"; + + /** + * Id of maximize/minimize icon of table - Distribution table. + */ + public static final String DS_MAX_MIN_TABLE_ICON = "ds.max.min.table.icon"; + + /** + * Software module table in upload UI. + */ + public static final String SM_TYPE_FILTER_BTN_ID = "sm.type.filter.btn."; + + /** + * Software module table details header caption id. + */ + public static final String TARGET_DETAILS_HEADER_LABEL_ID = "target.details.header.caption"; + + /** + * Software module table details header caption id. + */ + public static final String DISTRIBUTION_DETAILS_HEADER_LABEL_ID = "distribution.details.header.caption"; + + /** + * Software module table details vendor label id. + */ + public static final String DETAILS_VENDOR_LABEL_ID = "details.vendor"; + + /** + * Software module table details description label id. + */ + public static final String DETAILS_DESCRIPTION_LABEL_ID = "details.description"; + + /** + * Software module table details type label id. + */ + public static final String DETAILS_TYPE_LABEL_ID = "details.type"; + + /** + * Id of show filter button in software module table. + */ + public static final String SM_SHOW_FILTER_BUTTON_ID = "show.filter.layout"; + + /** + * Software module table in upload UI. + */ + public static final String DS_TYPE_FILTER_BTN_ID = "ds.type.filter.btn."; + + /** + * Id of target table search reset Icon. + */ + public static final String TARGET_TBL_SEARCH_RESET_ID = "target.search.rest.icon"; + + /** + * Id of the target table add Icon. + */ + public static final String TARGET_TBL_ADD_ICON_ID = "target.add"; + + /** + * Id of IP address label in target details. + */ + public static final String TARGET_IP_ADDRESS = "target.ip.address"; + + /** + * Id of Last query date label in target details. + */ + public static final String TARGET_LAST_QUERY_DT = "target.last.query.date"; + + /** + * Id of Controller Id label in target details. + */ + public static final String TARGET_CONTROLLER_ID = "target.controller.id"; + + /** + * Id of security token label in target details. + */ + public static final String TARGET_SECURITY_TOKEN = "target.security.token"; + + /** + * Id of maximize/minimize icon of table - Software module table. + */ + public static final String TARGET_MAX_MIN_TABLE_ICON = "target.max.min.table.icon"; + + /** + * Software module table in upload UI. + */ + public static final String SWM_DTLS_MAX_ASSIGN = "max.assign"; + + /** + * Documentation Link in Login view and menu. + */ + public static final String LINK_DOCUMENTATION = "link.documentation"; + + /** + * Demo Link in Login view and menu. + */ + public static final String LINK_DEMO = "link.demo"; + + /** + * Request account Link in Login view and menu. + */ + public static final String LINK_REQUESTACCOUNT = "link.requestaccount"; + + /** + * Support Link in Login view and menu. + */ + public static final String LINK_SUPPORT = "link.support"; + + /** + * User management Link in Login view and menu. + */ + public static final String LINK_USERMANAGEMENT = "link.usermanagement"; + + /** + * New Target tag add icon id. + */ + public static final String ADD_TARGET_TAG = "target.tag.add"; + + /** + * New distribution set tag add icon id. + */ + public static final String ADD_DISTRIBUTION_TAG = "distribution.tag.add"; + /** + * Bulk target upload - distribution set combo. + */ + public static final String BULK_UPLOAD_DS_COMBO = "bulkupload.ds.combo"; + + /** + * Bulk target upload - description. + */ + public static final String BULK_UPLOAD_DESC = "bulkupload.description"; + /** + * Bulk target upload - tag field. + */ + public static final String BULK_UPLOAD_TAG = "bulkupload.tag"; + /** + * Bulk target upload - count label. + */ + public static final String BULK_UPLOAD_COUNT = "bulkupload.upload.count"; + + /** + * Id of the target table bulk upload Icon. + */ + public static final String TARGET_TBL_BULK_UPLOAD_ICON_ID = "target.bulk.upload"; + + /** + * Id of target filter table search reset Icon. + */ + public static final String TARGET_FILTER_TBL_SEARCH_RESET_ID = "target.filter.search.rest.icon"; + + /** + * ID- Customfilter.Name. + */ + public static final String CUSTOM_FILTER_ADD_NAME = "custom.filter.add.name"; + + /** + * custom filter - delete button id. + */ + public static final String CUSTOM_FILTER_DELETE_ICON = "custom.filter.delete.button"; + + /** + * custom filter - update button id. + */ + public static final String CUSTOM_FILTER_DETAIL_LINK = "custom.filter.detail.link"; + + /** + * custom filter - save button id. + */ + public static final String CUSTOM_FILTER_SAVE_ICON = "custom.filter.save.button.Id"; + + /** + * ID-Custom target tag table. + */ + public static final String CUSTOM_TARGET_TAG_TABLE_ID = "custom.target.tag.tableId"; + + /** + * Target filter table id. + */ + public static final String TAEGET_FILTER_TABLE_ID = "target.query.filter.table.Id"; + + /** + * create or update target filter query - name label id. + */ + public static final String TARGET_FILTER_QUERY_NAME_LABEL_ID = "target.filter.name.label.id"; + + /** + * create or update target filter query - name layout id. + */ + public static final String TARGET_FILTER_QUERY_NAME_LAYOUT_ID = "target.filter.name.layout.id"; + /** + * * create or update target filter query - target table id. + */ + public static final String CUSTOM_FILTER_TARGET_TABLE_ID = "custom.filter.target.table.id"; + + /** + * Bulk upload notification button id. + */ + public static final String BULK_UPLOAD_STATUS_BUTTON = "bulk.upload.notification.id"; + + /** + * Target bulk upload minimize button id. + */ + public static final String BULK_UPLOAD_MINIMIZE_BUTTON_ID = "bulk.upload.minimize.button.id"; + + /** + * Target bulk upload minimize button id. + */ + + public static final String BULK_UPLOAD_CLOSE_BUTTON_ID = "bulk.upload.close.button.id"; + + /** + * Rollout list view - search box id. + */ + public static final String ROLLOUT_LIST_SEARCH_BOX_ID = "rollout.list.search.id"; + + /** + * Rollout list view - search reset icon id. + */ + public static final String ROLLOUT_LIST_SEARCH_RESET_ICON_ID = "rollout.list.search.reset.icon.id"; + + /** + * Rollout list view - add icon id. + */ + public static final String ROLLOUT_ADD_ICON_ID = "rollout.add.button.id"; + + /** + * Rollout list grid id. + */ + public static final String ROLLOUT_LIST_GRID_ID = "rollout.grid.id"; + + /** + * Rollout group list grid id. + */ + public static final String ROLLOUT_GROUP_LIST_GRID_ID = "rollout.group.grid.id"; + + /** + * Rollout group list grid id. + */ + public static final String ROLLOUT_GROUP_TARGETS_LIST_GRID_ID = "rollout.group.targets.grid.id"; + + /** + * Rollout text field name id. + */ + public static final String ROLLOUT_NAME_FIELD_ID = "rollout.name.field.id"; + /** + * Rollout number of groups id. + */ + public static final String ROLLOUT_NO_OF_GROUPS_ID = "rollout.no.ofgroups.id"; + + /** + * Rollout trigger threshold field if. + */ + public static final String ROLLOUT_TRIGGER_THRESOLD_ID = "rollout.trigger.thresold.id"; + + /** + * Rollout error thresold field id. + */ + public static final String ROLLOUT_ERROR_THRESOLD_ID = "rollout.error.thresold.id"; + + /** + * Rollout distribution set combo id. + */ + public static final String ROLLOUT_DS_ID = "rollout.ds.id"; + /** + * Rollout description field id. + */ + public static final String ROLLOUT_DESCRIPTION_ID = "rollout.description.id"; + /** + * Rollout target filter query combo id. + */ + public static final String ROLLOUT_TARGET_FILTER_COMBO_ID = "rollout.target.filter.combo.id"; + + /** + * Rollout action button id. + */ + public static final String ROLLOUT_ACTION_ID = "rollout.action.button.id"; + + /** + * Rollout start button id. + */ + public static final String ROLLOUT_RUN_BUTTON_ID = ROLLOUT_ACTION_ID + ".9"; + + /** + * Rollout pause button id. + */ + public static final String ROLLOUT_PAUSE_BUTTON_ID = ROLLOUT_ACTION_ID + ".10"; + + /** + * Rollout resume button id. + */ + public static final String ROLLOUT_UPDATE_BUTTON_ID = ROLLOUT_ACTION_ID + ".11"; + + /** + * Rollout status label id. + */ + public static final String ROLLOUT_STATUS_LABEL_ID = "rollout.status.id"; + + /** + * Rollout group status label id. + */ + public static final String ROLLOUT_GROUP_STATUS_LABEL_ID = "rollout.group.status.id"; + + /** + * Rollout % or count option group id. + */ + public static final String ROLLOUT_ERROR_THRESOLD_OPTION_ID = "rollout.error.thresold.option.id"; + + /** + * Rollout target filter query value text area id. + */ + public static final String ROLLOUT_TARGET_FILTER_QUERY_FIELD = "rollout.target.filter.query.field.id"; + + /** + * Rollout target view- close button id. + */ + public static final String ROLLOUT_TARGET_VIEW_CLOSE_BUTTON_ID = "rollout.group.target.close.id"; + /** + * Rollout group header caption. + */ + public static final String ROLLOUT_GROUP_HEADER_CAPTION = "rollout.group.header.caption"; + /** + * Rollout group close id. + */ + public static final String ROLLOUT_GROUP_CLOSE = "rollout.group.close.id"; + /** + * Rollout group targets count message label. + */ + public static final String ROLLOUT_GROUP_TARGET_LABEL = "rollout.group.target.label"; + + /** + * Action confirmation popup id. + */ + public static final String CONFIRMATION_POPUP_ID = "action.confirmation.popup.id"; + + /** + * Validation status icon . + */ + public static final String VALIDATION_STATUS_ICON_ID = "validation.status.icon"; + + /** + * Artifact upload status popup - minimize button id. + */ + public static final String UPLOAD_STATUS_POPUP_MINIMIZE_BUTTON_ID = "artifact.upload.minimize.button.id"; + + /** + * Artifact upload status popup - close button id. + */ + public static final String UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID = "artifact.upload.close.button.id"; + + /** + * Artifact upload status popup - resize button id. + */ + public static final String UPLOAD_STATUS_POPUP_RESIZE_BUTTON_ID = "artifact.upload.resize.button.id"; + + /** + * Artifact upload view - upload status button id. + */ + public static final String UPLOAD_STATUS_BUTTON = "artficat.upload.status.button.id"; + + /** + * Artifact uplaod view - uplod status popup id. + */ + public static final String UPLOAD_STATUS_POPUP_ID = "artifact.upload.status.popup.id"; + + /** + * Software module table - Manage metadata id. + */ + public static final String SW_TABLE_MANAGE_METADATA_ID = "swtable.manage.metadata.id"; + + /** + * Metadata key id. + */ + public static final String METADATA_KEY_FIELD_ID = "metadata.key.id"; + + /** + * Metadata value id. + */ + public static final String METADATA_VALUE_ID = "metadata.value.id"; + + /** + * Metadata add icon id. + */ + public static final String METADTA_ADD_ICON_ID = "metadata.add.icon.id"; + /** + * Metadata table id. + */ + public static final String METDATA_TABLE_ID = "metadata.table.id"; + + /** + * Distribution set table - Manage metadata id. + */ + public static final String DS_TABLE_MANAGE_METADATA_ID = "dstable.manage.metadata.id"; + + /** + * DistributionSet - Metadata button id. + */ + public static final String DS_METADATA_DETAIL_LINK = "distributionset.metadata.detail.link"; + + /** + * Metadata popup id. + */ + public static final String METADATA_POPUP_ID = "metadata.popup.id"; + + /** + * DistributionSet table details tab id in Distributions . + */ + public static final String DISTRIBUTIONSET_DETAILS_TABSHEET_ID = "distributionset.details.tabsheet"; + + /** + * Software module table details tab id in Distributions . + */ + public static final String DIST_SW_MODULE_DETAILS_TABSHEET_ID = "dist.sw.module.details.tabsheet"; + + /** + * Software Module - Metadata button id. + */ + public static final String SW_METADATA_DETAIL_LINK = "softwaremodule.metadata.detail.link"; + + /** + * /* Private Constructor. + */ + private SPUIComponentIdProvider() { + + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java index aae1da513..3a85bc791 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java @@ -205,6 +205,12 @@ public final class SPUIDefinitions { * Filter by status key. */ public static final String FILTER_BY_STATUS = "FilterByStatus"; + + /** + * Filter by overdue state key. + */ + public static final String FILTER_BY_OVERDUE_STATE = "FilterByOverdueState"; + /** * Filter by tag key. */ @@ -407,7 +413,7 @@ public final class SPUIDefinitions { /** * Filter by type layout width. */ - public static final float FILTER_BY_TYPE_WIDTH = 150.0F; + public static final float FILTER_BY_TYPE_WIDTH = 190.0F; /** * Confirmation jukebox type. diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss index c3cdb6eba..d1ae21f62 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss @@ -13,8 +13,9 @@ $unknown-color: $status-unknown-color; $in-sync-color: $signal-green-color; $pending-color: $signal-yellow-color; - $error-color: $signal-red-color; - $registered-color: $bosch-color-light-blue; + $error-color: $signal-red-color; + $overdue-color: $signal-black-color; + $registered-color: $signal-light-blue-color; //Filter by status buttons group alignment .target-status-filters { @@ -27,6 +28,10 @@ .status-button-layout { height: 40px !important; } + + .overdue-button-layout { + height: 40px !important; + } //Filter Button applied with below styles based on the color .unknownBtn { @@ -68,6 +73,16 @@ .errorBtn:active:after { border-color: $error-color; } + + .overdueBtn { + background: $overdue-color; + border: solid 3px $overdue-color; + } + + .overdueBtn:focus:after, + .overdueBtn:active:after { + border-color: $overdue-color; + } .registeredBtn { background: $registered-color; diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss index 81e0617b3..a3a6dc381 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss @@ -101,10 +101,12 @@ $details-tab-caption-font-scale: .8; //Generic text style $generic-text-font-scale: .85; -$status-unknown-color: #3085cb; +$status-unknown-color: #d5d5d5; $signal-green-color: #6eb553; $signal-yellow-color: #ff0; +$signal-light-blue-color: #3085cb; $signal-red-color: #f00; +$signal-black-color: #000; $signal-orange-color: #ffa500; $grey-light: #d5d5d5; diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss index 69dacfa57..3f70e139e 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss @@ -178,7 +178,7 @@ } .statusIconLightBlue { - color: $bosch-color-light-blue; + color: $signal-light-blue-color; } .v-button-statusIconLightBlue:after { @@ -219,7 +219,7 @@ pointer-events: auto !important; } .blueSpinner{ - @include valo-spinner($size: $v-font-size--small,$color: $bosch-color-light-blue); + @include valo-spinner($size: $v-font-size--small,$color: $signal-light-blue-color); pointer-events: auto !important; } diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss index 33ae2dd85..f4f91f2f6 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss @@ -44,7 +44,7 @@ .target-filter-spinner{ @include valo-spinner( $size: $v-font-size--small, - $color: $bosch-color-light-blue + $color: $signal-light-blue-color ); } diff --git a/hawkbit-ui/src/main/resources/messages.properties b/hawkbit-ui/src/main/resources/messages.properties index 6a68eeff8..c067d27f5 100644 --- a/hawkbit-ui/src/main/resources/messages.properties +++ b/hawkbit-ui/src/main/resources/messages.properties @@ -128,8 +128,6 @@ label.combobox.type = Select Type label.combobox.tag = Select Tag label.choose.tag = Choose Tag to update label.choose.tag.color = Choose Tag Color -label.filter = Filter: -label.target.filter.count = Total Targets: label.target.filtered.total = Total filtered targets : label.filter.selected = Selected: label.filter.shown = Shown: @@ -139,6 +137,7 @@ label.filter.selected = Selected : label.filter.shown = Shown : label.filter.targets = Filtered targets : label.filter.status = Status, +label.filter.overdue = Overdue, label.filter.tags = Tags, label.filter.text = Search Text label.filter.dist = Distribution, @@ -159,6 +158,7 @@ label.target.id = Controller Id : label.target.ip = Controller IP : label.target.security.token = Security token : label.filter.by.status = Filter by Status +label.filter.by.overdue = Filter by Overdue State label.target.controller.attrs = Controller attributes label.target.lastpolldate = Last poll : label.no.tag.assigned = NO TAG @@ -192,6 +192,7 @@ tooltip.status.registered = Registered tooltip.status.pending = Pending tooltip.status.error = Error tooltip.status.insync = In-sync +tooltip.status.overdue = Overdue tooltip.delete.module = Select and delete Software Module tooltip.forced.item=Forced update action tooltip.soft.item=Soft update action which interacts with an user as a attempt update action for example diff --git a/hawkbit-ui/src/main/resources/messages_de.properties b/hawkbit-ui/src/main/resources/messages_de.properties index e46be6b6e..fca470698 100644 --- a/hawkbit-ui/src/main/resources/messages_de.properties +++ b/hawkbit-ui/src/main/resources/messages_de.properties @@ -128,8 +128,6 @@ label.combobox.type = Select Type label.combobox.tag = Select Tag label.choose.tag = Choose Tag to update label.choose.tag.color = Choose Tag Color -label.filter = Filter: -label.target.filter.count = Total Targets: label.target.filtered.total = Total filtered targets : label.filter.selected = Selected: label.filter.shown = Shown: @@ -138,6 +136,7 @@ label.target.filter.count = Total Targets : label.filter.selected = Selected : label.filter.shown = Shown : label.filter.status = Status, +label.filter.overdue = Overdue, label.filter.tags = Tags, label.filter.text = Search Text label.filter.dist = Distribution, @@ -158,6 +157,7 @@ label.target.id = Controller Id : label.target.ip = Controller IP : label.target.security.token = Security token : label.filter.by.status = Filter by Status +label.filter.by.overdue = Filter by Overdue State label.target.controller.attrs = Controller attributes label.target.lastpolldate = Last poll : label.no.tag.assigned = NO TAG @@ -191,6 +191,7 @@ tooltip.status.registered = Registered tooltip.status.pending = Pending tooltip.status.error = Error tooltip.status.insync = In-sync +tooltip.status.overdue = Overdue tooltip.delete.module = Select and delete Software Module tooltip.forced.item=Forced update action tooltip.soft.item=Soft update action which interacts with an user as a attempt update action for example diff --git a/hawkbit-ui/src/main/resources/messages_en.properties b/hawkbit-ui/src/main/resources/messages_en.properties index 4328b83f8..dceb658df 100644 --- a/hawkbit-ui/src/main/resources/messages_en.properties +++ b/hawkbit-ui/src/main/resources/messages_en.properties @@ -127,8 +127,6 @@ label.combobox.type = Select Type label.combobox.tag = Select Tag label.choose.tag = Choose Tag to update label.choose.tag.color = Choose Tag Color -label.filter = Filter: -label.target.filter.count = Total Targets: label.target.filtered.total = Total filtered targets : label.filter.selected = Selected: label.filter.shown = Shown: @@ -138,6 +136,7 @@ label.target.filter.count = Total Targets : label.filter.selected = Selected : label.filter.shown = Shown : label.filter.status = Status, +label.filter.overdue = Overdue, label.filter.tags = Tags, label.filter.text = Search Text label.filter.dist = Distribution, @@ -158,6 +157,7 @@ label.target.id = Controller Id : label.target.ip = Controller IP : label.target.security.token = Security token : label.filter.by.status = Filter by Status +label.filter.by.overdue = Filter by Overdue State label.target.controller.attrs = Controller attributes label.target.lastpolldate = Last poll : label.no.tag.assigned = NO TAG @@ -191,6 +191,7 @@ tooltip.status.registered = Registered tooltip.status.pending = Pending tooltip.status.error = Error tooltip.status.insync = In-sync +tooltip.status.overdue = Overdue tooltip.delete.module = Select and delete Software Module tooltip.forced.item=Forced update action tooltip.soft.item=Soft update action which interacts with an user as a attempt update action for example From 76c3c96075a61f7e4f8341477a6baf50ca92804f Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Tue, 13 Sep 2016 16:19:53 +0200 Subject: [PATCH 03/17] Fix UI according to review feedback: - change color of overdue filter box - reduce width of filters section back to 150px - fix alignment of status boxes Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../ui/management/targettag/FilterByStatusLayout.java | 3 ++- .../org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java | 8 ++++---- .../VAADIN/themes/hawkbit/customstyles/filter-status.scss | 4 +++- .../themes/hawkbit/customstyles/hawkbitvariables.scss | 1 + hawkbit-ui/src/main/resources/messages.properties | 2 +- hawkbit-ui/src/main/resources/messages_de.properties | 2 +- hawkbit-ui/src/main/resources/messages_en.properties | 2 +- 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java index b393e1ff1..f32e7e8bd 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java @@ -107,7 +107,7 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click buttonLayout.addComponent(registered); buttonLayout.setComponentAlignment(registered, Alignment.MIDDLE_CENTER); addComponent(buttonLayout); - setComponentAlignment(buttonLayout, Alignment.MIDDLE_CENTER); + setComponentAlignment(buttonLayout, Alignment.MIDDLE_LEFT); final HorizontalLayout overdueLayout = new HorizontalLayout(); final Label overdueLabel = new LabelBuilder().name(i18n.get("label.filter.by.overdue")).buildLabel(); @@ -117,6 +117,7 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click overdueLayout.addComponent(overdueLabel); overdueLayout.setComponentAlignment(overdueLabel, Alignment.MIDDLE_LEFT); addComponent(overdueLayout); + setComponentAlignment(overdueLayout, Alignment.MIDDLE_LEFT); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java index 3a85bc791..78f1ce8ee 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java @@ -205,12 +205,12 @@ public final class SPUIDefinitions { * Filter by status key. */ public static final String FILTER_BY_STATUS = "FilterByStatus"; - + /** * Filter by overdue state key. */ public static final String FILTER_BY_OVERDUE_STATE = "FilterByOverdueState"; - + /** * Filter by tag key. */ @@ -413,7 +413,7 @@ public final class SPUIDefinitions { /** * Filter by type layout width. */ - public static final float FILTER_BY_TYPE_WIDTH = 190.0F; + public static final float FILTER_BY_TYPE_WIDTH = 150.0F; /** * Confirmation jukebox type. @@ -506,7 +506,7 @@ public final class SPUIDefinitions { /** * Get the locales - * + * * @return the availableLocales */ public static Set getAvailableLocales() { diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss index d1ae21f62..8cf27ab74 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/filter-status.scss @@ -14,8 +14,10 @@ $in-sync-color: $signal-green-color; $pending-color: $signal-yellow-color; $error-color: $signal-red-color; - $overdue-color: $signal-black-color; $registered-color: $signal-light-blue-color; + + //Overdue filter button color + $overdue-color: $signal-dark-blue-color; //Filter by status buttons group alignment .target-status-filters { diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss index a3a6dc381..96e6d9132 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/hawkbitvariables.scss @@ -105,6 +105,7 @@ $status-unknown-color: #d5d5d5; $signal-green-color: #6eb553; $signal-yellow-color: #ff0; $signal-light-blue-color: #3085cb; +$signal-dark-blue-color: #26547a; $signal-red-color: #f00; $signal-black-color: #000; $signal-orange-color: #ffa500; diff --git a/hawkbit-ui/src/main/resources/messages.properties b/hawkbit-ui/src/main/resources/messages.properties index c067d27f5..487665dcb 100644 --- a/hawkbit-ui/src/main/resources/messages.properties +++ b/hawkbit-ui/src/main/resources/messages.properties @@ -158,7 +158,7 @@ label.target.id = Controller Id : label.target.ip = Controller IP : label.target.security.token = Security token : label.filter.by.status = Filter by Status -label.filter.by.overdue = Filter by Overdue State +label.filter.by.overdue = Filter by Overdue label.target.controller.attrs = Controller attributes label.target.lastpolldate = Last poll : label.no.tag.assigned = NO TAG diff --git a/hawkbit-ui/src/main/resources/messages_de.properties b/hawkbit-ui/src/main/resources/messages_de.properties index fca470698..b77ed427b 100644 --- a/hawkbit-ui/src/main/resources/messages_de.properties +++ b/hawkbit-ui/src/main/resources/messages_de.properties @@ -157,7 +157,7 @@ label.target.id = Controller Id : label.target.ip = Controller IP : label.target.security.token = Security token : label.filter.by.status = Filter by Status -label.filter.by.overdue = Filter by Overdue State +label.filter.by.overdue = Filter by Overdue label.target.controller.attrs = Controller attributes label.target.lastpolldate = Last poll : label.no.tag.assigned = NO TAG diff --git a/hawkbit-ui/src/main/resources/messages_en.properties b/hawkbit-ui/src/main/resources/messages_en.properties index dceb658df..f6089364a 100644 --- a/hawkbit-ui/src/main/resources/messages_en.properties +++ b/hawkbit-ui/src/main/resources/messages_en.properties @@ -157,7 +157,7 @@ label.target.id = Controller Id : label.target.ip = Controller IP : label.target.security.token = Security token : label.filter.by.status = Filter by Status -label.filter.by.overdue = Filter by Overdue State +label.filter.by.overdue = Filter by Overdue label.target.controller.attrs = Controller attributes label.target.lastpolldate = Last poll : label.no.tag.assigned = NO TAG From 00aaed30279d413948d1770722f407aa236d9aea Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Thu, 15 Sep 2016 11:38:38 +0200 Subject: [PATCH 04/17] Fix findings from overdue review: * Introduce VirtualPropertyLookup interface * Remove Apache StrLookup from signature and use VirtualPropertyLookup * Use (internal) adapter to adapt VirtualPropertyLookup to StrLookup * Use interface instead of implementation for auto-wiring * Extract calculation for overdue_ts to service TimestampCalculator Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../RepositoryApplicationConfiguration.java | 11 --- .../jpa/JpaDeploymentManagement.java | 6 +- .../jpa/JpaDistributionSetManagement.java | 13 ++- .../jpa/JpaRolloutGroupManagement.java | 10 +- .../repository/jpa/JpaRolloutManagement.java | 7 +- .../repository/jpa/JpaSoftwareManagement.java | 12 ++- .../repository/jpa/JpaTagManagement.java | 9 +- .../jpa/JpaTargetFilterQueryManagement.java | 6 +- .../repository/jpa/JpaTargetManagement.java | 20 ++-- .../repository/jpa/TimestampCalculator.java | 45 +++++++++ .../repository/jpa/rsql/RSQLUtility.java | 99 ++++++++++--------- .../jpa/rsql/VirtualPropertyLookup.java | 27 +++++ .../rsql/VirtualPropertyMakroResolver.java | 76 -------------- .../jpa/rsql/VirtualPropertyResolver.java | 64 ++++++++++++ .../repository/jpa/rsql/RSQLUtilityTest.java | 35 ++++--- ....java => VirtualPropertyResolverTest.java} | 24 +++-- 16 files changed, 283 insertions(+), 181 deletions(-) create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java delete mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java rename hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/{VirtualPropertyMakroResolverTest.java => VirtualPropertyResolverTest.java} (81%) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java index 50a3d0b48..e1297e94e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java @@ -52,7 +52,6 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyMakroResolver; import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -392,14 +391,4 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { return new JpaEntityFactory(); } - /** - * {@link VirtualPropertyMakroResolver} bean. - * - * @return a new {@link VirtualPropertyMakroResolver} - */ - @Bean - @ConditionalOnMissingBean - public VirtualPropertyMakroResolver virtualPropertyMakroResolver() { - return new VirtualPropertyMakroResolver(); - } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java index 5a2c6fdda..54d6dadc0 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java @@ -54,6 +54,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; @@ -134,6 +135,9 @@ public class JpaDeploymentManagement implements DeploymentManagement { @Autowired private SystemSecurityContext systemSecurityContext; + @Autowired + private VirtualPropertyLookup virtualPropertyLookup; + @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Modifying @@ -605,7 +609,7 @@ public class JpaDeploymentManagement implements DeploymentManagement { } private Specification createSpecificationFor(final Target target, final String rsqlParam) { - final Specification spec = RSQLUtility.parse(rsqlParam, ActionFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, ActionFields.class, virtualPropertyLookup); return (root, query, cb) -> cb.and(spec.toPredicate(root, query, cb), cb.equal(root.get(JpaAction_.target), target)); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index e170ccad7..d1f9a68ef 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -43,6 +43,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata_; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; @@ -107,6 +108,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Autowired private TenantAware tenantAware; + @Autowired + private VirtualPropertyLookup virtualPropertyLookup; + @Override public DistributionSet findDistributionSetByIdWithDetails(final Long distid) { return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid)); @@ -286,7 +290,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Override public Page findDistributionSetTypesAll(final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, - DistributionSetTypeFields.class); + DistributionSetTypeFields.class, virtualPropertyLookup); return convertDsTPage(distributionSetTypeRepository.findAll(spec, pageable)); } @@ -352,7 +356,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { public Page findDistributionSetsAll(final String rsqlParam, final Pageable pageReq, final Boolean deleted) { - final Specification spec = RSQLUtility.parse(rsqlParam, DistributionSetFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, DistributionSetFields.class, + virtualPropertyLookup); final List> specList = new ArrayList<>(); if (deleted != null) { @@ -530,7 +535,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { /** * Method to get the latest distribution set based on ds ID after the * metadata changes for that distribution set. - * + * * @param distributionSet * Distribution set */ @@ -566,7 +571,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, - DistributionSetMetadataFields.class); + DistributionSetMetadataFields.class, virtualPropertyLookup); return convertMdPage( distributionSetMetadataRepository diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java index 9f63204b1..c977283dd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java @@ -33,6 +33,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; @@ -70,6 +71,9 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { @Autowired private EntityManager entityManager; + @Autowired + private VirtualPropertyLookup virtualPropertyLookup; + @Override public RolloutGroup findRolloutGroupById(final Long rolloutGroupId) { return rolloutGroupRepository.findOne(rolloutGroupId); @@ -92,7 +96,8 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { public Page findRolloutGroupsAll(final Rollout rollout, final String rsqlParam, final Pageable pageable) { - final Specification specification = RSQLUtility.parse(rsqlParam, RolloutGroupFields.class); + final Specification specification = RSQLUtility.parse(rsqlParam, RolloutGroupFields.class, + virtualPropertyLookup); return convertPage( rolloutGroupRepository @@ -145,7 +150,8 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { public Page findRolloutGroupTargets(final RolloutGroup rolloutGroup, final String rsqlParam, final Pageable pageable) { - final Specification rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class); + final Specification rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class, + virtualPropertyLookup); return convertTPage(targetRepository.findAll((root, query, criteriaBuilder) -> { final ListJoin rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java index 3a903ea89..f1138a6d7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java @@ -32,6 +32,7 @@ import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator; import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupConditionEvaluator; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.DistributionSet; @@ -114,6 +115,9 @@ public class JpaRolloutManagement implements RolloutManagement { @Autowired private CacheWriteNotify cacheWriteNotify; + @Autowired + private VirtualPropertyLookup virtualPropertyLookup; + @Autowired @Qualifier("asyncExecutor") private Executor executor; @@ -150,7 +154,8 @@ public class JpaRolloutManagement implements RolloutManagement { @Override public Page findAllWithDetailedStatusByPredicate(final String rsqlParam, final Pageable pageable) { - final Specification specification = RSQLUtility.parse(rsqlParam, RolloutFields.class); + final Specification specification = RSQLUtility.parse(rsqlParam, RolloutFields.class, + virtualPropertyLookup); final Page findAll = rolloutRepository.findAll(specification, pageable); setRolloutStatusDetails(findAll); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index 3f8c1a54b..9e612bc38 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -42,6 +42,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; @@ -102,6 +103,9 @@ public class JpaSoftwareManagement implements SoftwareManagement { @Autowired private ArtifactManagement artifactManagement; + @Autowired + private VirtualPropertyLookup virtualPropertyLookup; + @Override @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) @@ -312,7 +316,8 @@ public class JpaSoftwareManagement implements SoftwareManagement { @Override public Page findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class, + virtualPropertyLookup); return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable); } @@ -320,7 +325,8 @@ public class JpaSoftwareManagement implements SoftwareManagement { @Override public Page findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class, + virtualPropertyLookup); return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable); } @@ -609,7 +615,7 @@ public class JpaSoftwareManagement implements SoftwareManagement { final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, - SoftwareModuleMetadataFields.class); + SoftwareModuleMetadataFields.class, virtualPropertyLookup); return convertSmMdPage( softwareModuleMetadataRepository .findAll( diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java index e881d8ef8..22eb0914c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java @@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -74,6 +75,9 @@ public class JpaTagManagement implements TagManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; + @Autowired + private VirtualPropertyLookup virtualPropertyLookup; + @Override public TargetTag findTargetTag(final String name) { return targetTagRepository.findByNameEquals(name); @@ -147,7 +151,7 @@ public class JpaTagManagement implements TagManagement { @Override public Page findAllTargetTags(final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class, virtualPropertyLookup); return convertTPage(targetTagRepository.findAll(spec, pageable), pageable); } @@ -279,7 +283,8 @@ public class JpaTagManagement implements TagManagement { @Override public Page findAllDistributionSetTags(final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class); + final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class, + virtualPropertyLookup); return convertDsPage(distributionSetTagRepository.findAll(spec, pageable), pageable); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java index 693f9395e..39343d3a4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java @@ -16,7 +16,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyMakroResolver; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; @@ -46,7 +46,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme private TargetFilterQueryRepository targetFilterQueryRepository; @Autowired - private VirtualPropertyMakroResolver virtualPropMakroResolver; + private VirtualPropertyLookup virtualPropertyLookup; @Override @Modifying @@ -115,7 +115,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme @Override public boolean verifyTargetFilterQuerySyntax(final String query) { - RSQLUtility.parse(query, TargetFields.class, virtualPropMakroResolver); + RSQLUtility.parse(query, TargetFields.class, virtualPropertyLookup); return true; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 2528ed5ac..8bfa51d74 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -41,7 +41,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyMakroResolver; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.model.Target; @@ -104,7 +104,7 @@ public class JpaTargetManagement implements TargetManagement { private AfterTransactionCommitExecutor afterCommit; @Autowired - private VirtualPropertyMakroResolver virtualPropMakroResolver; + private VirtualPropertyLookup virtualPropertyLookup; @Override public Target findTargetByControllerID(final String controllerId) { @@ -157,13 +157,13 @@ public class JpaTargetManagement implements TargetManagement { @Override public Slice findTargetsAll(final TargetFilterQuery targetFilterQuery, final Pageable pageable) { return findTargetsBySpec( - RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropMakroResolver), + RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyLookup), pageable); } @Override public Page findTargetsAll(final String targetFilterQuery, final Pageable pageable) { - return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class, virtualPropMakroResolver), + return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class, virtualPropertyLookup), pageable); } @@ -232,7 +232,7 @@ public class JpaTargetManagement implements TargetManagement { final Pageable pageReq) { final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class, - virtualPropMakroResolver); + virtualPropertyLookup); return convertPage( targetRepository @@ -261,7 +261,7 @@ public class JpaTargetManagement implements TargetManagement { final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class, - virtualPropMakroResolver); + virtualPropertyLookup); return convertPage( targetRepository @@ -304,7 +304,7 @@ public class JpaTargetManagement implements TargetManagement { } if (overdueState != null) { specList.add( - TargetSpecifications.isOverdue(new VirtualPropertyMakroResolver().calculateOverdueTimestamp())); + TargetSpecifications.isOverdue(new TimestampCalculator().calculateOverdueTimestamp())); } if (installedOrAssignedDistributionSetId != null) { specList.add( @@ -561,7 +561,7 @@ public class JpaTargetManagement implements TargetManagement { targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty)); final Specification spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, - virtualPropMakroResolver); + virtualPropertyLookup); final List> specList = new ArrayList<>(); specList.add(spec); @@ -645,14 +645,14 @@ public class JpaTargetManagement implements TargetManagement { @Override public Long countTargetByTargetFilterQuery(final TargetFilterQuery targetFilterQuery) { final Specification specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, - virtualPropMakroResolver); + virtualPropertyLookup); return targetRepository.count(specs); } @Override public Long countTargetByTargetFilterQuery(final String targetFilterQuery) { final Specification specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class, - virtualPropMakroResolver); + virtualPropertyLookup); return targetRepository.count(specs); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java new file mode 100644 index 000000000..038ab263d --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java @@ -0,0 +1,45 @@ +package org.eclipse.hawkbit.repository.jpa; + +import java.time.Duration; +import java.time.Instant; + +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; +import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.springframework.stereotype.Service; + +@Service +public class TimestampCalculator { + + /** + * Calculates the overdue timestamp (overdue_ts) based on the + * current timestamp and the intervals for polling and poll-overdue: + *

+ * overdue_ts = now_ts - pollingInterval - + * pollingOverdueInterval;
+ * pollingInterval and pollingOverdueInterval are + * retrieved from tenant-specific system configuration. + * + * @return overdue_ts in milliseconds since Unix epoch as long + * value + */ + public long calculateOverdueTimestamp() { + long overdueTs = Instant.now().toEpochMilli() // + - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() // + - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis(); + return overdueTs; + } + + private Duration getDurationForKey(TenantConfigurationKey key) { + return DurationHelper.formattedStringToDuration(getRawStringForKey(key)); + } + + private String getRawStringForKey(TenantConfigurationKey key) { + return getTenantConfigurationManagement().getConfigurationValue(key, String.class).getValue(); + } + + protected TenantConfigurationManagement getTenantConfigurationManagement() { + return TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement(); + } +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index 228091494..a95172636 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -70,12 +70,12 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor; *

  • name==targetId1 or description==plugAndPlay or updateStatus==UNKNOWN
  • * *

    - * There is also a mechanism that allows to refer to known makros that can resolved by an optional {@link StrLookup} - * (cp. {@link VirtualPropertyMakroResolver}).
    + * There is also a mechanism that allows to refer to known macros that can resolved by an optional {@link StrLookup} + * (cp. {@link VirtualPropertyResolver}).
    * An example that queries for all overdue targets using the ${OVERDUE_TS} placeholder introduced by - * {@link VirtualPropertyMakroResolver} looks like this:
    + * {@link VirtualPropertyResolver} looks like this:
    * lastControllerRequestAt=le=${OVERDUE_TS}
    - * It is possible to escape a makro expression by using a second '$': $${OVERDUE_TS} would prevent the ${OVERDUE_TS} + * It is possible to escape a macro expression by using a second '$': $${OVERDUE_TS} would prevent the ${OVERDUE_TS} * token from being expanded. * */ @@ -99,6 +99,9 @@ public final class RSQLUtility { * @param fieldNameProvider * the enum class type which implements the * {@link FieldNameProvider} + * @param virtualPropertyLookup + * holds the logic how the known macros have to be resolved; may + * be null * @return an specification which can be used with JPA * @throws RSQLParameterUnsupportedFieldException * if a field in the RSQL string is used but not provided by the @@ -107,29 +110,8 @@ public final class RSQLUtility { * if the RSQL syntax is wrong */ public static & FieldNameProvider, T> Specification parse(final String rsql, - final Class fieldNameProvider) { - return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, new VirtualPropertyMakroResolver()); - } - - /** - * parses an RSQL valid string into an JPA {@link Specification} which then can be used to filter for JPA entities - * with the given RSQL query. - * - * @param rsql - * the rsql query - * @param fieldNameProvider - * the enum class type which implements the {@link FieldNameProvider} - * @param makroLookup - * holds the logic how the known makros have to be resolved; may be null - * @return an 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 & FieldNameProvider, T> Specification parse(final String rsql, - final Class fieldNameProvider, StrLookup makroLookup) { - return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, makroLookup); + final Class fieldNameProvider, VirtualPropertyLookup virtualPropertyLookup) { + return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, virtualPropertyLookup); } /** @@ -160,12 +142,13 @@ public final class RSQLUtility { private final String rsql; private final Class enumType; - private final StrLookup makroLookup; + private final VirtualPropertyLookup virtualPropertyLookup; - private RSQLSpecification(final String rsql, final Class enumType, StrLookup makroLookup) { + private RSQLSpecification(final String rsql, final Class enumType, + VirtualPropertyLookup virtualPropertyLookup) { this.rsql = rsql; this.enumType = enumType; - this.makroLookup = makroLookup; + this.virtualPropertyLookup = virtualPropertyLookup; } @Override @@ -174,7 +157,7 @@ public final class RSQLUtility { final Node rootNode = parseRsql(rsql); final JpqQueryRSQLVisitor jpqQueryRSQLVisitor = new JpqQueryRSQLVisitor<>(root, cb, enumType, - makroLookup); + virtualPropertyLookup); final List accept = rootNode., String> accept(jpqQueryRSQLVisitor); if (accept != null && !accept.isEmpty()) { @@ -204,18 +187,19 @@ public final class RSQLUtility { private final Root root; private final CriteriaBuilder cb; private final Class enumType; - private final StrLookup makroLookup; + private final VirtualPropertyLookup virtualPropertyLookup; private final StrSubstitutor substitutor; private final SimpleTypeConverter simpleTypeConverter; private JpqQueryRSQLVisitor(final Root root, final CriteriaBuilder cb, final Class enumType, - StrLookup makroLookup) { + VirtualPropertyLookup virtualPropertyLookup) { this.root = root; this.cb = cb; this.enumType = enumType; - this.makroLookup = makroLookup; - this.substitutor = new StrSubstitutor(makroLookup, StrSubstitutor.DEFAULT_PREFIX, + this.virtualPropertyLookup = virtualPropertyLookup; + this.substitutor = new StrSubstitutor(new StrLookupAdapter(virtualPropertyLookup), + StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); simpleTypeConverter = new SimpleTypeConverter(); } @@ -387,13 +371,10 @@ public final class RSQLUtility { private Object convertValueIfNecessary(final ComparisonNode node, final A fieldName, final String value, final Path fieldPath) { // in case the value of an rsql query e.g. type==application is an - // enum we need to - // handle it separately because JPA needs the correct java-type to - // build an - // expression. So String and numeric values JPA can do it by it's - // own but not for - // classes like enums. So we need to transform the given value - // string into the enum + // enum we need to handle it separately because JPA needs the + // correct java-type to build an expression. So String and numeric + // values JPA can do it by it's own but not for classes like enums. + // So we need to transform the given value string into the enum // class. final Class javaType = fieldPath.getJavaType(); if (javaType != null && javaType.isEnum()) { @@ -445,8 +426,7 @@ public final class RSQLUtility { return Enum.valueOf(tmpEnumType, value.toUpperCase()); } catch (final IllegalArgumentException e) { // we could not transform the given string value into the enum - // type, so ignore - // it and return null and do not filter + // type, so ignore it and return null and do not filter LOGGER.info("given value {} cannot be transformed into the correct enum type {}", value.toUpperCase(), javaType); LOGGER.debug("value cannot be transformed to an enum", e); @@ -461,12 +441,13 @@ public final class RSQLUtility { private List mapToPredicate(final ComparisonNode node, final Path fieldPath, final List values, final List transformedValues, final A enumField) { // only 'equal' and 'notEqual' can handle transformed value like - // enums. The JPA API - // cannot handle object types for greaterThan etc methods. + // enums. The JPA API cannot handle object types for greaterThan etc + // methods. final Object transformedValue = transformedValues.get(0); final String value; - if (makroLookup != null) { // if substitutor is available, replace makros ... + if (virtualPropertyLookup != null) { // if lookup is available, + // replace macros ... value = substitutor.replace(values.get(0)); } else { value = values.get(0); @@ -611,4 +592,28 @@ public final class RSQLUtility { } } + + /** + * Adapts the VirtualPropertyLookup to StrLookup. + */ + final static class StrLookupAdapter extends StrLookup { + + private VirtualPropertyLookup virtualPropertyLookup; + + /** + * Constructor. + * + * @param virtualPropertyLookup + * the lookup to adapt. + */ + StrLookupAdapter(VirtualPropertyLookup virtualPropertyLookup) { + this.virtualPropertyLookup = virtualPropertyLookup; + } + + @Override + public String lookup(String key) { + return virtualPropertyLookup.lookup(key); + } + + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java new file mode 100644 index 000000000..09952a4fc --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2016 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.rsql; + +/** + * Implementations map a placeholder to the associated value. + *

    + * This is used in context of string replacement. + */ +public interface VirtualPropertyLookup { + + /** + * Looks up a placeholder to the associated value. + * + * @param placeholder + * the virtual property that should be resolved by a value + * @return the value for the placeholder; may be null if no + * value could be found for the given placeholder; + */ + public String lookup(String placeholder); +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java deleted file mode 100644 index 5ade64630..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolver.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2016 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository.jpa.rsql; - -import java.time.Duration; -import java.time.Instant; - -import org.apache.commons.lang3.text.StrLookup; -import org.apache.commons.lang3.text.StrSubstitutor; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; -import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; - -/** - * Adds makro capabilities to RSQL expressions that are used to filter for targets. - *

    - * Some (virtual) properties do not have a representation in the database (in general these properties are time-related, - * or more explicitly, they deal with time intervals).
    - * Such a virtual property needs to be calculated on Java-side before it may be used in a target filter query that is - * passed to the database. Therefore a placeholder is used in the RSQL expression that is expanded in the - * {@link RSQLUtility} by a {@link StrSubstitutor}. This {@link StrSubstitutor} is configured with an instance of - * {@link VirtualPropertyMakroResolver} to resolve the known makros. - *

    - * A virtual property may either be a system value like the current date (aka now_ts) or a value derived from - * (tenant-specific) system configuration (e.g. overdue_ts). - *

    - * Known values are:
    - *

      - *
    • now_ts: maps to system UTC time in milliseconds since Unix epoch as long value
    • - *
    • overdue_ts: is a calculated value: overdue_ts = now_ts - pollingInterval - pollingOverdueInterval - * ; pollingInterval and pollingOverdueInterval are retrieved from tenant-specific system configuration.
    • - *
    - * - */ -public class VirtualPropertyMakroResolver extends StrLookup { - - @Override - public String lookup(String rhs) { - String resolved = null; - - if ("now_ts".equals(rhs.toLowerCase())) { - resolved = String.valueOf(Instant.now().toEpochMilli()); - } else if ("overdue_ts".equals(rhs.toLowerCase())) { - resolved = String.valueOf(calculateOverdueTimestamp()); - } - return resolved; - } - - public long calculateOverdueTimestamp() { - long overdueTs = Instant.now().toEpochMilli() // - - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() // - - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis(); - return overdueTs; - } - - private Duration getDurationForKey(TenantConfigurationKey key) { - return DurationHelper.formattedStringToDuration(getRawStringForKey(key)); - } - - private String getRawStringForKey(TenantConfigurationKey key) { - return getTenantConfigurationManagement().getConfigurationValue(key, String.class).getValue(); - } - - TenantConfigurationManagement getTenantConfigurationManagement() { - return TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement(); - } - - -} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java new file mode 100644 index 000000000..39aed8786 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2016 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.rsql; + +import java.time.Instant; + +import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Adds macro capabilities to RSQL expressions that are used to filter for + * targets. + *

    + * Some (virtual) properties do not have a representation in the database (in + * general these properties are time-related, or more explicitly, they deal with + * time intervals).
    + * Such a virtual property needs to be calculated on Java-side before it may be + * used in a target filter query that is passed to the database. Therefore a + * placeholder is used in the RSQL expression that is expanded in the + * {@link RSQLUtility}. + *

    + * A virtual property may either be a system value like the current date (aka + * now_ts) or a value derived from (tenant-specific) system + * configuration (e.g. overdue_ts). + *

    + * Known values are:
    + *

      + *
    • now_ts: maps to system UTC time in milliseconds since Unix epoch + * as long value
    • + *
    • overdue_ts: is a calculated value: overdue_ts = now_ts - + * pollingInterval - pollingOverdueInterval; pollingInterval and + * pollingOverdueInterval are retrieved from tenant-specific system + * configuration.
    • + *
    + */ +@Component +public class VirtualPropertyResolver implements VirtualPropertyLookup { + + @Autowired + private TimestampCalculator timestampCalculator; + + @Override + public String lookup(String rhs) { + String resolved = null; + + if ("now_ts".equals(rhs.toLowerCase())) { + resolved = String.valueOf(Instant.now().toEpochMilli()); + } else if ("overdue_ts".equals(rhs.toLowerCase())) { + resolved = String.valueOf(getTimestampCalculator().calculateOverdueTimestamp()); + } + return resolved; + } + + TimestampCalculator getTimestampCalculator() { + return timestampCalculator; + } +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index e7b5ba592..1e73bbe24 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -20,7 +20,6 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.persistence.metamodel.Attribute; -import org.apache.commons.lang3.text.StrLookup; import org.eclipse.hawkbit.repository.DistributionSetFields; import org.eclipse.hawkbit.repository.FieldNameProvider; import org.eclipse.hawkbit.repository.SoftwareModuleFields; @@ -28,6 +27,7 @@ import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; @@ -49,11 +49,14 @@ import ru.yandex.qatools.allure.annotations.Stories; public class RSQLUtilityTest { @Spy - VirtualPropertyMakroResolver makroResolver = new VirtualPropertyMakroResolver(); + VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(); @Mock TenantConfigurationManagement confMgmt; + @Mock + TimestampCalculator timestampCalculator; + @Mock private Root baseSoftwareModuleRootMock; @@ -271,7 +274,7 @@ public class RSQLUtilityTest { @Test @Description("Tests the resolution of overdue_ts placeholder in context of a RSQL expression.") - public void correctRsqlWithOverdueMakro() { + public void correctRsqlWithOverdueMacro() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String overdueProp = "overdue_ts"; final String overduePropPlaceholder = "${" + overdueProp + "}"; @@ -283,12 +286,12 @@ public class RSQLUtilityTest { .thenReturn(mock(Predicate.class)); // test - Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMakroLookup()) + Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); // verfication - verify(makroResolver, times(1)).lookup(overdueProp); - // the makro is already replaced when passed to #lessThanOrEqualTo -> the method is never invoked with the + verify(macroResolver, times(1)).lookup(overdueProp); + // the macro is already replaced when passed to #lessThanOrEqualTo -> the method is never invoked with the // placeholder: verify(criteriaBuilderMock, never()).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), eq(overduePropPlaceholder)); @@ -296,7 +299,7 @@ public class RSQLUtilityTest { @Test @Description("Tests RSQL expression with an unknown placeholder.") - public void correctRsqlWithUnknownMakro() { + public void correctRsqlWithUnknownMacro() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String overdueProp = "unknown"; final String overduePropPlaceholder = "${" + overdueProp + "}"; @@ -308,24 +311,30 @@ public class RSQLUtilityTest { .thenReturn(mock(Predicate.class)); // test - Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMakroLookup()) + Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); // verfication - verify(makroResolver, times(1)).lookup(overdueProp); - // the makro is unknown and hence never replaced -> #lessThanOrEqualTo is invoked with the placeholder: + verify(macroResolver, times(1)).lookup(overdueProp); + // the macro is unknown and hence never replaced -> #lessThanOrEqualTo is invoked with the placeholder: verify(criteriaBuilderMock, times(1)).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), eq(overduePropPlaceholder)); } - public StrLookup setupMakroLookup() { + public VirtualPropertyLookup setupMacroLookup() { when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class)) .thenReturn(TEST_POLLING_TIME_INTERVAL); when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); - when(makroResolver.getTenantConfigurationManagement()).thenReturn(confMgmt); - return makroResolver; + when(macroResolver.getTimestampCalculator()).thenReturn(new TimestampCalculator() { + @Override + protected TenantConfigurationManagement getTenantConfigurationManagement() { + return confMgmt; + } + }); + + return macroResolver; } @SuppressWarnings("unchecked") diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java similarity index 81% rename from hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolverTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index f18783d5f..e21ec7bcd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyMakroResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -15,6 +15,7 @@ import java.time.Instant; import org.apache.commons.lang3.text.StrSubstitutor; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.junit.Before; @@ -31,10 +32,10 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Unit Tests - Repository") @Stories("Placeholder resolution for virtual properties") @RunWith(MockitoJUnitRunner.class) -public class VirtualPropertyMakroResolverTest { +public class VirtualPropertyResolverTest { @Spy - VirtualPropertyMakroResolver resolverUnderTest = new VirtualPropertyMakroResolver(); + VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(); @Mock TenantConfigurationManagement confMgmt; @@ -55,14 +56,21 @@ public class VirtualPropertyMakroResolverTest { .thenReturn(TEST_POLLING_TIME_INTERVAL); when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); - when(resolverUnderTest.getTenantConfigurationManagement()).thenReturn(confMgmt); - this.substitutor = new StrSubstitutor(resolverUnderTest, StrSubstitutor.DEFAULT_PREFIX, + when(resolverUnderTest.getTimestampCalculator()).thenReturn(new TimestampCalculator() { + @Override + protected TenantConfigurationManagement getTenantConfigurationManagement() { + return confMgmt; + } + }); + + this.substitutor = new StrSubstitutor(new RSQLUtility.StrLookupAdapter(resolverUnderTest), + StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); } @Test - @Description("Tests resolution of NOW_TS by using a StrSubstitutor configured with the VirtualPropertyMakroResolver.") + @Description("Tests resolution of NOW_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.") public void resolveNowTimestampPlaceholder() { String placeholder = "${NOW_TS}"; String testString = "lhs=lt=" + placeholder; @@ -72,7 +80,7 @@ public class VirtualPropertyMakroResolverTest { } @Test - @Description("Tests resolution of OVERDUE_TS by using a StrSubstitutor configured with the VirtualPropertyMakroResolver.") + @Description("Tests resolution of OVERDUE_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.") public void resolveOverdueTimestampPlaceholder() { String placeholder = "${OVERDUE_TS}"; String testString = "lhs=lt=" + placeholder; @@ -82,7 +90,7 @@ public class VirtualPropertyMakroResolverTest { } @Test - @Description("Tests case insensititity of VirtualPropertyMakroResolver.") + @Description("Tests case insensititity of VirtualPropertyResolver.") public void resolveOverdueTimestampPlaceholderLowerCase() { String placeholder = "${overdue_ts}"; String testString = "lhs=lt=" + placeholder; @@ -92,7 +100,7 @@ public class VirtualPropertyMakroResolverTest { } @Test - @Description("Tests VirtualPropertyMakroResolver with a placeholder unknown to VirtualPropertyMakroResolver.") + @Description("Tests VirtualPropertyResolver with a placeholder unknown to VirtualPropertyResolver.") public void handleUnknownPlaceholder() { String placeholder = "${unknown}"; String testString = "lhs=lt=" + placeholder; From b790072d1f8afdf54e0f8f1961184bf44c7c44ed Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Wed, 21 Sep 2016 17:18:45 +0200 Subject: [PATCH 05/17] Adapt to renamed UIComponentIdProvider; use capital letters for constant Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../targettag/FilterByStatusLayout.java | 8 +- .../ui/utils/SPUIComponentIdProvider.java | 846 ------------------ .../ui/utils/UIComponentIdProvider.java | 4 + 3 files changed, 8 insertions(+), 850 deletions(-) delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java index f32e7e8bd..bef6409cd 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/FilterByStatusLayout.java @@ -54,7 +54,7 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click @Autowired private ManagementUIState managementUIState; - private static final String overdueCaption = "overdue"; + private static final String OVERDUE_CAPTION = "overdue"; private Button unknown; private Button inSync; @@ -168,8 +168,8 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click registered = SPUIComponentProvider.getButton(UIComponentIdProvider.REGISTERED_STATUS_ICON, TargetUpdateStatus.REGISTERED.toString(), i18n.get("tooltip.status.registered"), SPUIButtonDefinitions.SP_BUTTON_STATUS_STYLE, false, FontAwesome.SQUARE, SPUIButtonStyleSmall.class); - overdue = SPUIComponentProvider.getButton(SPUIComponentIdProvider.OVERDUE_STATUS_ICON, - overdueCaption, i18n.get("tooltip.status.overdue"), + overdue = SPUIComponentProvider.getButton(UIComponentIdProvider.OVERDUE_STATUS_ICON, + OVERDUE_CAPTION, i18n.get("tooltip.status.overdue"), SPUIButtonDefinitions.SP_BUTTON_STATUS_STYLE, false, FontAwesome.SQUARE, SPUIButtonStyleSmall.class); applyStatusBtnStyle(); unknown.setData("filterStatusOne"); @@ -212,7 +212,7 @@ public class FilterByStatusLayout extends VerticalLayout implements Button.Click processErrorFilterStatus(); } else if (event.getButton().getCaption().equalsIgnoreCase(TargetUpdateStatus.REGISTERED.toString())) { processRegisteredFilterStatus(); - } else if (event.getButton().getCaption().equalsIgnoreCase(overdueCaption)) { + } else if (event.getButton().getCaption().equalsIgnoreCase(OVERDUE_CAPTION)) { processOverdueFilterStatus(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java deleted file mode 100644 index 13d7ced1a..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java +++ /dev/null @@ -1,846 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.ui.utils; - -/** - * Interface to provide the unchanged constants. - * - * - * - * - * - */ -public final class SPUIComponentIdProvider { - /** - * ID-Target. - */ - public static final String TARGET_TABLE_ID = "target.tableId"; - /** - * ID- Targ.Cont ID. - */ - public static final String TARGET_ADD_CONTROLLER_ID = "target.add.ctrlId"; - /** - * ID-Targ.Name. - */ - public static final String TARGET_ADD_NAME = "target.add.name"; - /** - * ID-Targ.Disc. - */ - public static final String TARGET_ADD_DESC = "target.add.desc"; - /** - * ID-Targ.DEL. - */ - public static final String TARGET_DELETE_ALL = "target.delete.all"; - /** - * ID-SW.DEL. - */ - public static final String SW_DELETE_ALL = "swmodule.delete.all"; - /** - * ID-Targ.Edit.icon. - */ - public static final String TARGET_EDIT_ICON = "target.edit.icon"; - /** - * ID-Targ.PIN. - */ - public static final String TARGET_PIN_ICON = "target.pin.icon"; - - /** - * Target search text id. - */ - public static final String TARGET_TEXT_FIELD = "target.search.textfield"; - - /** - * ID for add target filter icon - */ - public static final String TARGET_FILTER_ADD_ICON_ID = "target.filter.add.id"; - - /** - * ID-Dist. - */ - public static final String DIST_TABLE_ID = "dist.tableId"; - /** - * ID-Dist.Name. - */ - public static final String DIST_ADD_NAME = "dist.add.name"; - /** - * ID-Dist.Version. - */ - public static final String DIST_ADD_VERSION = "dist.add.version"; - /** - * ID-Dist.DistSetType. - */ - public static final String DIST_ADD_DISTSETTYPE = "dist.add.distsettype"; - /** - * ID-Dist.desc. - */ - public static final String DIST_ADD_DESC = "dist.add.desc"; - /** - * /** ID-Dist.DELETE. - */ - public static final String DIST_DELETE_ALL = "dist.delete.all"; - /** - * ID-Dist.MigCheck. - */ - public static final String DIST_ADD_MIGRATION_CHECK = "dist.add.required.migration"; - /** - * ID-Dist.Search.icon. - */ - public static final String DIST_SEARCH_ICON = "dist.search.rest.icon"; - /** - * ID-Dist.Search.txt. - */ - public static final String DIST_SEARCH_TEXTFIELD = "dist.search.textfield"; - /** - * ID - Dist.Add. - */ - public static final String DIST_ADD_ICON = "dist.add.icon"; - /** - * ID for Distribution Tag ComboBox - */ - public static final String DIST_TAG_COMBO = "dist.tag.combo"; - /** - * ID-Dist.PIN. - */ - public static final String DIST_PIN_BUTTON = "dist.pin.button"; - /** - * ID - soft.module.name. - */ - public static final String SOFT_MODULE_NAME = "soft.module.name"; - /** - * ID - soft.module.version. - */ - public static final String SOFT_MODULE_VERSION = "soft.module.version"; - - /** - * ID - soft.module.vendor. - */ - public static final String SOFT_MODULE_VENDOR = "soft.module.vendor"; - - /** - * ID - Save Assign. - */ - public static final String SAVE_ASSIGNMENT = "save.actions.popup.assign"; - - /** - * ID - Discard Assign. - */ - public static final String DISCARD_ASSIGNMENT = "discard.actions.popup.assign"; - - /** - * ID - Delete Distribution SetType Save. - */ - public static final String SAVE_DELETE_DIST_SET_TYPE = "save.actions.popup.delete.dist.set.type"; - - /** - * ID - Discard Distribution SetType. - */ - public static final String DISCARD_DIST_SET_TYPE = "save.actions.popup.discard.dist.set.type"; - /** - * ID Delete Software Module Type save. - */ - public static final String SAVE_DELETE_SW_MODULE_TYPE = "save.actions.popup.delete.sw.module.type"; - - /** - * ID - Discard SW Module Type. - */ - public static final String DISCARD_SW_MODULE_TYPE = "save.actions.popup.discard.sw.module.type"; - - /** - * Action history table cancel Id. - */ - public static final String ACTION_DETAILS_SOFT_ID = "action.details.soft.group"; - - /** - * ID - Label. - */ - public static final String ACTION_LABEL = "save.actions.popup.actionMsg"; - /** - * ID - Count. - */ - public static final String COUNT_LABEL = "count.message.label"; - /** - * UNKNOWN_STATUS_ICON ID. - */ - public static final String UNKNOWN_STATUS_ICON = "unknown.status.icon"; - /** - * INSYNCH_STATUS_ICON ID. - */ - public static final String INSYNCH_STATUS_ICON = "insynch.status.icon"; - /** - * PENDING_STATUS_ICON ID. - */ - public static final String PENDING_STATUS_ICON = "pending.status.icon"; - /** - * ERROR_STATUS_ICON ID. - */ - public static final String ERROR_STATUS_ICON = "error.status.icon"; - /** - * REGISTERED_STATUS_ICON ID. - */ - public static final String REGISTERED_STATUS_ICON = "registered.status.icon"; - /** - * OVERDUE_STATUS_ICON ID. - */ - public static final String OVERDUE_STATUS_ICON = "overdue.status.icon"; - /** - * DROP filter icon id. - */ - public static final String TARGET_DROP_FILTER_ICON = "target.drop.filter.icon"; - - /** - * Pending action button id. - */ - public static final String PENDING_ACTION_BUTTON = "pending.action.button"; - /** - * Action history table Id. - */ - public static final String ACTION_HISTORY_TABLE_ID = "action.history.tableId"; - - /** - * Action history table cancel Id. - */ - public static final String ACTION_HISTORY_TABLE_CANCEL_ID = "action.history.table.action.cancel"; - - /** - * Action history table force Id. - */ - public static final String ACTION_HISTORY_TABLE_FORCE_ID = "action.history.table.action.force"; - - /** - * Action history table force quit Id. - */ - public static final String ACTION_HISTORY_TABLE_FORCE_QUIT_ID = "action.history.table.action.force.quit"; - - /** - * Target filter wrapper id. - */ - public static final String TARGET_FILTER_WRAPPER_ID = "target-drop-filter"; - - /** - * Delete button wrapper id. - */ - public static final String DELETE_BUTTON_WRAPPER_ID = "delete.button"; - /** - * tag color preview button id. - */ - public static final String TAG_COLOR_PREVIEW_ID = "tag.color.preview"; - /** - * Id for ColorPickerLayout - */ - public static final String COLOR_PICKER_LAYOUT = "color.picker.layout"; - /** - * Id for ColorPickerLayout's red slider - */ - public static final String COLOR_PICKER_RED_SLIDER = "color.picker.red.slider"; - /** - * Id for Color preview field with the color code - */ - public static final String COLOR_PREVIEW_FIELD = "color-preview-field"; - /** - * Id for OptionGroup Create/Update tag - */ - public static final String OPTION_GROUP = "create.update.tag"; - /** - * Confirmation dialogue OK button id. - */ - public static final String OK_BUTTON = "ok.button"; - /** - * Upload - type button id. - */ - public static final String UPLOAD_TYPE_BUTTON_PREFIX = "upload.type.button."; - /** - * Upload - process button id. - */ - public static final String UPLOAD_PROCESS_BUTTON = "upload.process.button"; - /** - * Upload - discard button id. - */ - public static final String UPLOAD_DISCARD_BUTTON = "upload.discard.button"; - - /** - * Upload - artifact detail close button. - */ - public static final String UPLOAD_ARTIFACT_DETAILS_CLOSE = "upload.artifactdetails.close.button"; - /** - * Upload - artifact detail table. - */ - public static final String UPLOAD_ARTIFACT_DETAILS_TABLE = "upload.artifactdetails.table"; - - /** - * Upload - artifact upload button. - */ - public static final String UPLOAD_BUTTON = "artifact.upload.button"; - /** - * Upload - process button id. - */ - public static final String UPLOAD_DISCARD_DETAILS_BUTTON = "upload.discard.details.button"; - /** - * Upload - delete button id. - */ - public static final String UPLOAD_DELETE_ICON = "upload.delete.button"; - - /** - * Upload- file delete button id. - */ - public static final String UPLOAD_FILE_DELETE_ICON = "upload.file.delete.button"; - /** - * ID-Dist. - */ - public static final String UPLOAD_SOFTWARE_MODULE_TABLE = "upload.swModule.table"; - - /** - * Upload result popup close button. - */ - public static final String UPLOAD_ARTIFACT_RESULT_POPUP_CLOSE = "upload.resultwindow.close.button"; - - /** - * Upload result popup close button. - */ - public static final String UPLOAD_ARTIFACT_RESULT_CLOSE = "upload.results.close.button"; - /** - * Upload - artifact result table. - */ - public static final String UPLOAD_RESULT_TABLE = "upload.result.table"; - /** - * Upload - software module search text id. - */ - public static final String SW_MODULE_SEARCH_TEXT_FIELD = "swmodule.search.textfield"; - /** - * Upload - software module search reset icon id. - */ - public static final String SW_MODULE_SEARCH_RESET_ICON = "sw.search.reset.icon"; - - /** - * Upload - artifact upload error reason. - */ - public static final String UPLOAD_ERROR_REASON = "upload-error-reason"; - - /** - * Upload - artifact upload - Software module add button. - */ - public static final String SW_MODULE_ADD_BUTTON = "sw.module.add.button"; - - /** - * Upload - artifact upload - Software module type combo id. - */ - public static final String SW_MODULE_TYPE = "sw.module.select.type"; - - /** - * Upload - artifact upload - Software module description. - */ - public static final String ADD_SW_MODULE_DESCRIPTION = "sw.module.description"; - - /** - * ID-Targ.Detail.icon. - */ - public static final String SW_TABLE_ATRTIFACT_DETAILS_ICON = "swmodule.artifact.details.icon"; - - /** - * Artifact upload - sw module edit button id. - */ - public static final String UPLOAD_SW_MODULE_EDIT_BUTTON = "swmodule.edit.button"; - - /** - * Ds edit button id. - */ - public static final String DS_EDIT_BUTTON = "ds.edit.button"; - /** - * Upload Artifact details max table Id. - */ - public static final String UPLOAD_ARTIFACT_DETAILS_TABLE_MAX = "upload.artifactdetails.table.max"; - - /** - * Target tag close button. - */ - public static final String HIDE_TARGET_TAGS = "hide.target.tags"; - - /** - * Show target tag layout icon. - */ - public static final String SHOW_TARGET_TAGS = "show.target.tags.icon"; - - /** - * ID-Target tag table. - */ - public static final String TARGET_TAG_TABLE_ID = "target.tag.tableId"; - /** - * ID-Distibution tag table. - */ - public static final String DISTRIBUTION_TAG_TABLE_ID = "distriution.tag.tableId"; - /** - * ID-Software module type table. - */ - public static final String SW_MODULE_TYPE_TABLE_ID = "sw.module.type.table"; - - /** - * ID-Target tag table. - */ - public static final String DISTRIBUTION_SET_TYPE_TABLE_ID = "dist.set.type.tableId"; - - /** - * Tab sheet id. - */ - public static final String TARGET_DETAILS_TABSHEET = "target.details.tabsheet"; - /** - * Tab sheet id. - */ - public static final String DISTRIBUTION_DETAILS_TABSHEET = "distribution.details.tabsheet."; - - /** - * Combobox id. - */ - public static final String SYSTEM_CONFIGURATION_DEFAULTDIS_COMBOBOX = "default.disset.combobox"; - - /** - * Button save id. - */ - public static final String SYSTEM_CONFIGURATION_SAVE = "system.configuration.save"; - - /** - * ID for save button in pop-up-windows instance of commonDialogWindow - */ - public static final String SAVE_BUTTON = "common.dialog.window.save"; - - /** - * ID for cancel button in pop-up-windows instance of commonDialogWindow - */ - public static final String CANCEL_BUTTON = "common.dialog.window.cancel"; - - /** - * Cancel button is. - */ - public static final String SYSTEM_CONFIGURATION_CANCEL = "system.configuration.cancel"; - - /** - * Id of maximize/minimize icon of table - Software module table. - */ - public static final String SW_MAX_MIN_TABLE_ICON = "sw.max.min.table.icon"; - - /** - * Id of maximize/minimize icon of table - Distribution table. - */ - public static final String DS_MAX_MIN_TABLE_ICON = "ds.max.min.table.icon"; - - /** - * Software module table in upload UI. - */ - public static final String SM_TYPE_FILTER_BTN_ID = "sm.type.filter.btn."; - - /** - * Software module table details header caption id. - */ - public static final String TARGET_DETAILS_HEADER_LABEL_ID = "target.details.header.caption"; - - /** - * Software module table details header caption id. - */ - public static final String DISTRIBUTION_DETAILS_HEADER_LABEL_ID = "distribution.details.header.caption"; - - /** - * Software module table details vendor label id. - */ - public static final String DETAILS_VENDOR_LABEL_ID = "details.vendor"; - - /** - * Software module table details description label id. - */ - public static final String DETAILS_DESCRIPTION_LABEL_ID = "details.description"; - - /** - * Software module table details type label id. - */ - public static final String DETAILS_TYPE_LABEL_ID = "details.type"; - - /** - * Id of show filter button in software module table. - */ - public static final String SM_SHOW_FILTER_BUTTON_ID = "show.filter.layout"; - - /** - * Software module table in upload UI. - */ - public static final String DS_TYPE_FILTER_BTN_ID = "ds.type.filter.btn."; - - /** - * Id of target table search reset Icon. - */ - public static final String TARGET_TBL_SEARCH_RESET_ID = "target.search.rest.icon"; - - /** - * Id of the target table add Icon. - */ - public static final String TARGET_TBL_ADD_ICON_ID = "target.add"; - - /** - * Id of IP address label in target details. - */ - public static final String TARGET_IP_ADDRESS = "target.ip.address"; - - /** - * Id of Last query date label in target details. - */ - public static final String TARGET_LAST_QUERY_DT = "target.last.query.date"; - - /** - * Id of Controller Id label in target details. - */ - public static final String TARGET_CONTROLLER_ID = "target.controller.id"; - - /** - * Id of security token label in target details. - */ - public static final String TARGET_SECURITY_TOKEN = "target.security.token"; - - /** - * Id of maximize/minimize icon of table - Software module table. - */ - public static final String TARGET_MAX_MIN_TABLE_ICON = "target.max.min.table.icon"; - - /** - * Software module table in upload UI. - */ - public static final String SWM_DTLS_MAX_ASSIGN = "max.assign"; - - /** - * Documentation Link in Login view and menu. - */ - public static final String LINK_DOCUMENTATION = "link.documentation"; - - /** - * Demo Link in Login view and menu. - */ - public static final String LINK_DEMO = "link.demo"; - - /** - * Request account Link in Login view and menu. - */ - public static final String LINK_REQUESTACCOUNT = "link.requestaccount"; - - /** - * Support Link in Login view and menu. - */ - public static final String LINK_SUPPORT = "link.support"; - - /** - * User management Link in Login view and menu. - */ - public static final String LINK_USERMANAGEMENT = "link.usermanagement"; - - /** - * New Target tag add icon id. - */ - public static final String ADD_TARGET_TAG = "target.tag.add"; - - /** - * New distribution set tag add icon id. - */ - public static final String ADD_DISTRIBUTION_TAG = "distribution.tag.add"; - /** - * Bulk target upload - distribution set combo. - */ - public static final String BULK_UPLOAD_DS_COMBO = "bulkupload.ds.combo"; - - /** - * Bulk target upload - description. - */ - public static final String BULK_UPLOAD_DESC = "bulkupload.description"; - /** - * Bulk target upload - tag field. - */ - public static final String BULK_UPLOAD_TAG = "bulkupload.tag"; - /** - * Bulk target upload - count label. - */ - public static final String BULK_UPLOAD_COUNT = "bulkupload.upload.count"; - - /** - * Id of the target table bulk upload Icon. - */ - public static final String TARGET_TBL_BULK_UPLOAD_ICON_ID = "target.bulk.upload"; - - /** - * Id of target filter table search reset Icon. - */ - public static final String TARGET_FILTER_TBL_SEARCH_RESET_ID = "target.filter.search.rest.icon"; - - /** - * ID- Customfilter.Name. - */ - public static final String CUSTOM_FILTER_ADD_NAME = "custom.filter.add.name"; - - /** - * custom filter - delete button id. - */ - public static final String CUSTOM_FILTER_DELETE_ICON = "custom.filter.delete.button"; - - /** - * custom filter - update button id. - */ - public static final String CUSTOM_FILTER_DETAIL_LINK = "custom.filter.detail.link"; - - /** - * custom filter - save button id. - */ - public static final String CUSTOM_FILTER_SAVE_ICON = "custom.filter.save.button.Id"; - - /** - * ID-Custom target tag table. - */ - public static final String CUSTOM_TARGET_TAG_TABLE_ID = "custom.target.tag.tableId"; - - /** - * Target filter table id. - */ - public static final String TAEGET_FILTER_TABLE_ID = "target.query.filter.table.Id"; - - /** - * create or update target filter query - name label id. - */ - public static final String TARGET_FILTER_QUERY_NAME_LABEL_ID = "target.filter.name.label.id"; - - /** - * create or update target filter query - name layout id. - */ - public static final String TARGET_FILTER_QUERY_NAME_LAYOUT_ID = "target.filter.name.layout.id"; - /** - * * create or update target filter query - target table id. - */ - public static final String CUSTOM_FILTER_TARGET_TABLE_ID = "custom.filter.target.table.id"; - - /** - * Bulk upload notification button id. - */ - public static final String BULK_UPLOAD_STATUS_BUTTON = "bulk.upload.notification.id"; - - /** - * Target bulk upload minimize button id. - */ - public static final String BULK_UPLOAD_MINIMIZE_BUTTON_ID = "bulk.upload.minimize.button.id"; - - /** - * Target bulk upload minimize button id. - */ - - public static final String BULK_UPLOAD_CLOSE_BUTTON_ID = "bulk.upload.close.button.id"; - - /** - * Rollout list view - search box id. - */ - public static final String ROLLOUT_LIST_SEARCH_BOX_ID = "rollout.list.search.id"; - - /** - * Rollout list view - search reset icon id. - */ - public static final String ROLLOUT_LIST_SEARCH_RESET_ICON_ID = "rollout.list.search.reset.icon.id"; - - /** - * Rollout list view - add icon id. - */ - public static final String ROLLOUT_ADD_ICON_ID = "rollout.add.button.id"; - - /** - * Rollout list grid id. - */ - public static final String ROLLOUT_LIST_GRID_ID = "rollout.grid.id"; - - /** - * Rollout group list grid id. - */ - public static final String ROLLOUT_GROUP_LIST_GRID_ID = "rollout.group.grid.id"; - - /** - * Rollout group list grid id. - */ - public static final String ROLLOUT_GROUP_TARGETS_LIST_GRID_ID = "rollout.group.targets.grid.id"; - - /** - * Rollout text field name id. - */ - public static final String ROLLOUT_NAME_FIELD_ID = "rollout.name.field.id"; - /** - * Rollout number of groups id. - */ - public static final String ROLLOUT_NO_OF_GROUPS_ID = "rollout.no.ofgroups.id"; - - /** - * Rollout trigger threshold field if. - */ - public static final String ROLLOUT_TRIGGER_THRESOLD_ID = "rollout.trigger.thresold.id"; - - /** - * Rollout error thresold field id. - */ - public static final String ROLLOUT_ERROR_THRESOLD_ID = "rollout.error.thresold.id"; - - /** - * Rollout distribution set combo id. - */ - public static final String ROLLOUT_DS_ID = "rollout.ds.id"; - /** - * Rollout description field id. - */ - public static final String ROLLOUT_DESCRIPTION_ID = "rollout.description.id"; - /** - * Rollout target filter query combo id. - */ - public static final String ROLLOUT_TARGET_FILTER_COMBO_ID = "rollout.target.filter.combo.id"; - - /** - * Rollout action button id. - */ - public static final String ROLLOUT_ACTION_ID = "rollout.action.button.id"; - - /** - * Rollout start button id. - */ - public static final String ROLLOUT_RUN_BUTTON_ID = ROLLOUT_ACTION_ID + ".9"; - - /** - * Rollout pause button id. - */ - public static final String ROLLOUT_PAUSE_BUTTON_ID = ROLLOUT_ACTION_ID + ".10"; - - /** - * Rollout resume button id. - */ - public static final String ROLLOUT_UPDATE_BUTTON_ID = ROLLOUT_ACTION_ID + ".11"; - - /** - * Rollout status label id. - */ - public static final String ROLLOUT_STATUS_LABEL_ID = "rollout.status.id"; - - /** - * Rollout group status label id. - */ - public static final String ROLLOUT_GROUP_STATUS_LABEL_ID = "rollout.group.status.id"; - - /** - * Rollout % or count option group id. - */ - public static final String ROLLOUT_ERROR_THRESOLD_OPTION_ID = "rollout.error.thresold.option.id"; - - /** - * Rollout target filter query value text area id. - */ - public static final String ROLLOUT_TARGET_FILTER_QUERY_FIELD = "rollout.target.filter.query.field.id"; - - /** - * Rollout target view- close button id. - */ - public static final String ROLLOUT_TARGET_VIEW_CLOSE_BUTTON_ID = "rollout.group.target.close.id"; - /** - * Rollout group header caption. - */ - public static final String ROLLOUT_GROUP_HEADER_CAPTION = "rollout.group.header.caption"; - /** - * Rollout group close id. - */ - public static final String ROLLOUT_GROUP_CLOSE = "rollout.group.close.id"; - /** - * Rollout group targets count message label. - */ - public static final String ROLLOUT_GROUP_TARGET_LABEL = "rollout.group.target.label"; - - /** - * Action confirmation popup id. - */ - public static final String CONFIRMATION_POPUP_ID = "action.confirmation.popup.id"; - - /** - * Validation status icon . - */ - public static final String VALIDATION_STATUS_ICON_ID = "validation.status.icon"; - - /** - * Artifact upload status popup - minimize button id. - */ - public static final String UPLOAD_STATUS_POPUP_MINIMIZE_BUTTON_ID = "artifact.upload.minimize.button.id"; - - /** - * Artifact upload status popup - close button id. - */ - public static final String UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID = "artifact.upload.close.button.id"; - - /** - * Artifact upload status popup - resize button id. - */ - public static final String UPLOAD_STATUS_POPUP_RESIZE_BUTTON_ID = "artifact.upload.resize.button.id"; - - /** - * Artifact upload view - upload status button id. - */ - public static final String UPLOAD_STATUS_BUTTON = "artficat.upload.status.button.id"; - - /** - * Artifact uplaod view - uplod status popup id. - */ - public static final String UPLOAD_STATUS_POPUP_ID = "artifact.upload.status.popup.id"; - - /** - * Software module table - Manage metadata id. - */ - public static final String SW_TABLE_MANAGE_METADATA_ID = "swtable.manage.metadata.id"; - - /** - * Metadata key id. - */ - public static final String METADATA_KEY_FIELD_ID = "metadata.key.id"; - - /** - * Metadata value id. - */ - public static final String METADATA_VALUE_ID = "metadata.value.id"; - - /** - * Metadata add icon id. - */ - public static final String METADTA_ADD_ICON_ID = "metadata.add.icon.id"; - /** - * Metadata table id. - */ - public static final String METDATA_TABLE_ID = "metadata.table.id"; - - /** - * Distribution set table - Manage metadata id. - */ - public static final String DS_TABLE_MANAGE_METADATA_ID = "dstable.manage.metadata.id"; - - /** - * DistributionSet - Metadata button id. - */ - public static final String DS_METADATA_DETAIL_LINK = "distributionset.metadata.detail.link"; - - /** - * Metadata popup id. - */ - public static final String METADATA_POPUP_ID = "metadata.popup.id"; - - /** - * DistributionSet table details tab id in Distributions . - */ - public static final String DISTRIBUTIONSET_DETAILS_TABSHEET_ID = "distributionset.details.tabsheet"; - - /** - * Software module table details tab id in Distributions . - */ - public static final String DIST_SW_MODULE_DETAILS_TABSHEET_ID = "dist.sw.module.details.tabsheet"; - - /** - * Software Module - Metadata button id. - */ - public static final String SW_METADATA_DETAIL_LINK = "softwaremodule.metadata.detail.link"; - - /** - * /* Private Constructor. - */ - private SPUIComponentIdProvider() { - - } -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java index e3475d20d..baef02ab5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java @@ -189,6 +189,10 @@ public final class UIComponentIdProvider { * REGISTERED_STATUS_ICON ID. */ public static final String REGISTERED_STATUS_ICON = "registered.status.icon"; + /** + * OVERDUE_STATUS_ICON ID. + */ + public static final String OVERDUE_STATUS_ICON = "overdue.status.icon"; /** * DROP filter icon id. */ From 07a158534f063b14917b404eff3d33bcee67bc62 Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Thu, 22 Sep 2016 10:28:08 +0200 Subject: [PATCH 06/17] Fix issues from static code analysis Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../hawkbit/repository/FilterParams.java | 151 ++++++++++++++++++ .../hawkbit/repository/TargetManagement.java | 29 +--- .../repository/jpa/JpaTargetManagement.java | 54 ++++--- .../jpa/rsql/VirtualPropertyLookup.java | 1 + .../jpa/rsql/VirtualPropertyResolver.java | 4 +- .../jpa/TargetManagementSearchTest.java | 12 +- .../targettable/TargetBeanQuery.java | 12 +- .../management/targettable/TargetTable.java | 35 ++-- 8 files changed, 215 insertions(+), 83 deletions(-) create mode 100644 hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java new file mode 100644 index 000000000..2c50ce41b --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java @@ -0,0 +1,151 @@ +package org.eclipse.hawkbit.repository; + +import java.util.Collection; + +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; + +/** + * Encapsulates a set of filters that may be specified (optionally). Properties + * that are not specified (e.g. null for simple properties) When + * applied, these filters are AND-gated. + * + */ +public class FilterParams { + + Collection filterByStatus; + Boolean overdueState; + String filterBySearchText; + Boolean selectTargetWithNoTag; + String[] filterByTagNames; + Long filterByDistributionId; + + public FilterParams(Long filterByDistributionId, Collection filterByStatus, + Boolean overdueState, String filterBySearchText, Boolean selectTargetWithNoTag, + String... filterByTagNames) { + this.filterByStatus = filterByStatus; + this.overdueState = overdueState; + this.filterBySearchText = filterBySearchText; + this.filterByDistributionId = filterByDistributionId; + this.selectTargetWithNoTag = selectTargetWithNoTag; + this.filterByTagNames = filterByTagNames; + } + + /** + * Gets {@link DistributionSet#getId()} to filter the result.
    + * If set to null this filter is disabled. + * + * @return {@link DistributionSet#getId()} to filter the result + */ + public Long getFilterByDistributionId() { + return filterByDistributionId; + } + + /** + * Sets {@link DistributionSet#getId()} to filter the result. + * + * @param filterByDistributionId + */ + public void setFilterByDistributionId(Long filterByDistributionId) { + this.filterByDistributionId = filterByDistributionId; + } + + /** + * Gets a collection of target states to filter for.
    + * If set to null this filter is disabled. + * + * @return collection of target states to filter for + */ + public Collection getFilterByStatus() { + return filterByStatus; + } + + /** + * Sets the collection of target states to filter for. + * + * @param filterByStatus + */ + public void setFilterByStatus(Collection filterByStatus) { + this.filterByStatus = filterByStatus; + } + + /** + * Gets the flag for overdue filter; if set to true, the + * overdue filter is activated. Overdued targets a targets that did not + * respond during the configured intervals: poll_itvl + overdue_itvl.
    + * If set to null this filter is disabled. + * + * @return flag for overdue filter activation + */ + public Boolean getOverdueState() { + return overdueState; + } + + /** + * Sets the flag for overdue filter; if set to true, the + * overdue filter is activated. + * + * @param overdueState + */ + public void setOverdueState(Boolean overdueState) { + this.overdueState = overdueState; + } + + /** + * Gets the search text to filter for. This is used to find targets having + * the text anywhere in name or description
    + * If set to null this filter is disabled. + * + * @return the search text to filter for + */ + public String getFilterBySearchText() { + return filterBySearchText; + } + + /** + * Sets the search text to filter for. + * + * @param filterBySearchText + */ + public void setFilterBySearchText(String filterBySearchText) { + this.filterBySearchText = filterBySearchText; + } + + /** + * Gets the flag indicating if tagging filter is used.
    + * If set to null this filter is disabled. + * + * @return the flag indicating if tagging filter is used + */ + public Boolean getSelectTargetWithNoTag() { + return selectTargetWithNoTag; + } + + /** + * Sets the flag indicating if tagging filter is used. + * + * @param selectTargetWithNoTag + */ + public void setSelectTargetWithNoTag(Boolean selectTargetWithNoTag) { + this.selectTargetWithNoTag = selectTargetWithNoTag; + } + + /** + * Gets the tags that are used to filter for. The activation of this filter + * is done by {@link #setSelectTargetWithNoTag(Boolean)}. + * + * @return the tags that are used to filter for + */ + public String[] getFilterByTagNames() { + return filterByTagNames; + } + + /** + * Sets the tags that are used to filter for. + * + * @param filterByTagNames + */ + public void setFilterByTagNames(String[] filterByTagNames) { + this.filterByTagNames = filterByTagNames; + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 40fd7cc27..97cce6436 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -480,36 +480,15 @@ public interface TargetManagement { * the page request to page the result set * @param orderByDistributionId * {@link DistributionSet#getId()} to be ordered by - * @param filterByDistributionId - * {@link DistributionSet#getId()} to be filter the result. Set - * to null in case this is not required. - * @param filterByStatus - * find targets having this {@link TargetUpdateStatus}s. Set to - * null in case this is not required. - * @param overdueState - * find targets that are overdue (targets that did not respond - * during the configured intervals: poll_itvl + overdue_itvl). - * @param filterBySearchText - * to find targets having the text anywhere in name or - * description. Set null in case this is not - * required. - * @param installedOrAssignedDistributionSetId - * to find targets having the {@link DistributionSet} as - * installed or assigned. Set to null in case this - * is not required. - * @param filterByTagNames - * to find targets which are having any one in this tag names. - * Set null in case this is not required. - * @param selectTargetWithNoTag - * flag to select targets with no tag assigned + * @param filterParams + * the filters to apply; only filters are enabled that have + * non-null value; filters are AND-gated * @return a paged result {@link Page} of the {@link Target}s in a defined * order. */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Slice findTargetsAllOrderByLinkedDistributionSet(@NotNull Pageable pageable, - @NotNull Long orderByDistributionId, Long filterByDistributionId, - Collection filterByStatus, Boolean overdueState, String filterBySearchText, - Boolean selectTargetWithNoTag, String... filterByTagNames); + @NotNull Long orderByDistributionId, FilterParams filterParams); /** * retrieves a list of {@link Target}s by their controller ID with details, diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 8bfa51d74..756f337a1 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -27,6 +27,7 @@ import javax.persistence.criteria.Order; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import org.eclipse.hawkbit.repository.FilterParams; import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; @@ -281,8 +282,10 @@ public class JpaTargetManagement implements TargetManagement { public Slice findTargetByFilters(final Pageable pageable, final Collection status, final Boolean overdueState, final String searchText, final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, final String... tagNames) { - final List> specList = buildSpecificationList(status, overdueState, searchText, - installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); + final List> specList = buildSpecificationList( + new FilterParams(installedOrAssignedDistributionSetId, status, overdueState, searchText, + selectTargetWithNoTag, tagNames), + true); return findByCriteriaAPI(pageable, specList); } @@ -290,31 +293,35 @@ public class JpaTargetManagement implements TargetManagement { public Long countTargetByFilters(final Collection status, final Boolean overdueState, final String searchText, final Long installedOrAssignedDistributionSetId, final Boolean selectTargetWithNoTag, final String... tagNames) { - final List> specList = buildSpecificationList(status, overdueState, searchText, - installedOrAssignedDistributionSetId, selectTargetWithNoTag, true, tagNames); + final List> specList = buildSpecificationList( + new FilterParams(installedOrAssignedDistributionSetId, status, overdueState, searchText, + selectTargetWithNoTag, tagNames), + true); return countByCriteriaAPI(specList); } - private static List> buildSpecificationList(final Collection status, - final Boolean overdueState, final String searchText, final Long installedOrAssignedDistributionSetId, - final Boolean selectTargetWithNoTag, final boolean fetch, final String... tagNames) { + private static List> buildSpecificationList(final FilterParams filterParams, + final boolean fetch) { final List> specList = new ArrayList<>(); - if (status != null && !status.isEmpty()) { - specList.add(TargetSpecifications.hasTargetUpdateStatus(status, fetch)); + if (filterParams.getFilterByStatus() != null && !filterParams.getFilterByStatus().isEmpty()) { + specList.add(TargetSpecifications.hasTargetUpdateStatus(filterParams.getFilterByStatus(), fetch)); } - if (overdueState != null) { + if (filterParams.getOverdueState() != null) { specList.add( TargetSpecifications.isOverdue(new TimestampCalculator().calculateOverdueTimestamp())); } - if (installedOrAssignedDistributionSetId != null) { + if (filterParams.getFilterByDistributionId() != null) { specList.add( - TargetSpecifications.hasInstalledOrAssignedDistributionSet(installedOrAssignedDistributionSetId)); + TargetSpecifications + .hasInstalledOrAssignedDistributionSet(filterParams.getFilterByDistributionId())); } - if (!Strings.isNullOrEmpty(searchText)) { - specList.add(TargetSpecifications.likeNameOrDescriptionOrIp(searchText)); + if (!Strings.isNullOrEmpty(filterParams.getFilterBySearchText())) { + specList.add(TargetSpecifications.likeNameOrDescriptionOrIp(filterParams.getFilterBySearchText())); } - if (selectTargetWithNoTag != null && (selectTargetWithNoTag || (tagNames != null && tagNames.length > 0))) { - specList.add(TargetSpecifications.hasTags(tagNames, selectTargetWithNoTag)); + if (filterParams.getSelectTargetWithNoTag() != null && (filterParams.getSelectTargetWithNoTag() + || (filterParams.getFilterByTagNames() != null && filterParams.getFilterByTagNames().length > 0))) { + specList.add(TargetSpecifications.hasTags(filterParams.getFilterByTagNames(), + filterParams.getSelectTargetWithNoTag())); } return specList; } @@ -428,10 +435,8 @@ public class JpaTargetManagement implements TargetManagement { @Override public Slice findTargetsAllOrderByLinkedDistributionSet(final Pageable pageable, - final Long orderByDistributionId, final Long filterByDistributionId, - final Collection filterByStatus, final Boolean overdueState, - final String filterBySearchText, - final Boolean selectTargetWithNoTag, final String... filterByTagNames) { + final Long orderByDistributionId, final FilterParams filterParams) { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery(JpaTarget.class); final Root targetRoot = query.from(JpaTarget.class); @@ -454,8 +459,7 @@ public class JpaTargetManagement implements TargetManagement { // build the specifications and then to predicates necessary by the // given filters final Predicate[] specificationsForMultiSelect = specificationsToPredicate( - buildSpecificationList(filterByStatus, overdueState, filterBySearchText, filterByDistributionId, - selectTargetWithNoTag, true, filterByTagNames), + buildSpecificationList(filterParams, true), targetRoot, query, cb); // if we have some predicates then add it to the where clause of the @@ -529,9 +533,9 @@ public class JpaTargetManagement implements TargetManagement { targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty)); final Predicate[] specificationsForMultiSelect = specificationsToPredicate( - buildSpecificationList(filterByStatus, overdueState, filterBySearchText, - installedOrAssignedDistributionSetId, - selectTargetWithNoTag, false, filterByTagNames), + buildSpecificationList(new FilterParams(installedOrAssignedDistributionSetId, filterByStatus, + overdueState, filterBySearchText, + selectTargetWithNoTag, filterByTagNames), false), targetRoot, multiselect, cb); // if we have some predicates then add it to the where clause of the diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java index 09952a4fc..95e34a89f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java @@ -13,6 +13,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql; *

    * This is used in context of string replacement. */ +@FunctionalInterface public interface VirtualPropertyLookup { /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java index 39aed8786..c1e87c43a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java @@ -50,9 +50,9 @@ public class VirtualPropertyResolver implements VirtualPropertyLookup { public String lookup(String rhs) { String resolved = null; - if ("now_ts".equals(rhs.toLowerCase())) { + if ("now_ts".equalsIgnoreCase(rhs)) { resolved = String.valueOf(Instant.now().toEpochMilli()); - } else if ("overdue_ts".equals(rhs.toLowerCase())) { + } else if ("overdue_ts".equalsIgnoreCase(rhs)) { resolved = String.valueOf(getTimestampCalculator().calculateOverdueTimestamp()); } return resolved; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java index e4c6a15b9..5dee43411 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementSearchTest.java @@ -16,21 +16,16 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Map; -import java.util.stream.Collector; import java.util.stream.Collectors; -import java.util.stream.IntStream; -import org.eclipse.hawkbit.ControllerPollProperties; +import org.eclipse.hawkbit.repository.FilterParams; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; -import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; @@ -39,7 +34,6 @@ import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Slice; import com.google.common.collect.Lists; @@ -746,7 +740,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { targInstalled = sendUpdateActionStatusToTargets(ds, targInstalled, Status.FINISHED, "installed"); final Slice result = targetManagement.findTargetsAllOrderByLinkedDistributionSet(pageReq, ds.getId(), - null, null, null, null, Boolean.FALSE, new String[0]); + new FilterParams(null, null, null, null, Boolean.FALSE, new String[0])); final Comparator byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId()); @@ -801,7 +795,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest { targInstalled = sendUpdateActionStatusToTargets(ds, targInstalled, Status.FINISHED, "installed"); final Slice result = targetManagement.findTargetsAllOrderByLinkedDistributionSet(pageReq, ds.getId(), - null, null, Boolean.TRUE, null, Boolean.FALSE, new String[0]); + new FilterParams(null, null, Boolean.TRUE, null, Boolean.FALSE, new String[0])); final Comparator byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId()); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index 6459935ab..ee1f59159 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -11,14 +11,14 @@ package org.eclipse.hawkbit.ui.management.targettable; import static org.apache.commons.lang3.ArrayUtils.isEmpty; import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.isNotNullOrEmpty; import static org.eclipse.hawkbit.ui.utils.SPUIDefinitions.TARGET_TABLE_CREATE_AT_SORT_ORDER; -import static org.springframework.data.domain.Sort.Direction.ASC; -import static org.springframework.data.domain.Sort.Direction.DESC; +import static org.springframework.data.domain.Sort.Direction.*; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import org.eclipse.hawkbit.repository.FilterParams; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.model.DistributionSet; @@ -40,6 +40,7 @@ import org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery; import org.vaadin.addons.lazyquerycontainer.QueryDefinition; import com.google.common.base.Strings; +import com.google.common.primitives.Booleans; /** * Simple implementation of generics bean query which dynamically loads a batch @@ -115,7 +116,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { if (pinnedDistId != null) { targetBeans = getTargetManagement().findTargetsAllOrderByLinkedDistributionSet( new OffsetBasedPageRequest(startIndex, SPUIDefinitions.PAGE_SIZE, sort), pinnedDistId, - distributionId, status, overdueState, searchText, noTagClicked, targetTags); + new FilterParams(distributionId, status, overdueState, searchText, noTagClicked, targetTags)); } else if (null != targetFilterQuery) { targetBeans = getTargetManagement().findTargetsAll(targetFilterQuery, new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort)); @@ -185,8 +186,9 @@ public class TargetBeanQuery extends AbstractBeanQuery { } private Boolean anyFilterSelected() { - if (status == null && distributionId == null && Strings.isNullOrEmpty(searchText) && !isTagSelected() - && !isOverdueFilterEnabled()) { + int enabledFiltersCount = Booleans.countTrue(status != null, distributionId != null, + !Strings.isNullOrEmpty(searchText), isTagSelected(), isOverdueFilterEnabled()); + if (enabledFiltersCount == 0) { return false; } return true; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java index 9773f2adb..5d1e6a46e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java @@ -8,14 +8,7 @@ */ package org.eclipse.hawkbit.ui.management.targettable; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_DISTRIBUTION; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_TAG; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_TARGET_FILTER_QUERY; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_TEXT; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_DISTRIBUTION; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_TAG; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_TARGET_FILTER_QUERY; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_TEXT; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.*; import java.util.ArrayList; import java.util.Collection; @@ -26,6 +19,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.hawkbit.repository.FilterParams; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; @@ -63,11 +57,11 @@ import org.eclipse.hawkbit.ui.management.state.TargetTableFilters; import org.eclipse.hawkbit.ui.utils.AssignInstalledDSTooltipGenerator; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; -import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import org.eclipse.hawkbit.ui.utils.TableColumn; +import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -902,26 +896,33 @@ public class TargetTable extends AbstractTable { pinnedDistId = managementUIState.getTargetTableFilters().getPinnedDistId().get(); } - final long size = getTargetsCountWithFilter(totalTargetsCount, status, overdueState, targetTags, distributionId, - searchText, noTagClicked, pinnedDistId); + final long size = getTargetsCountWithFilter(totalTargetsCount, pinnedDistId, + new FilterParams(distributionId, status, overdueState, searchText, noTagClicked, targetTags)); if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { managementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); } } - private long getTargetsCountWithFilter(final long totalTargetsCount, final Collection status, - final Boolean overdueState, final String[] targetTags, final Long distributionId, final String searchText, - final Boolean noTagClicked, final Long pinnedDistId) { + private long getTargetsCountWithFilter(final long totalTargetsCount, + // final Collection status, + // final Boolean overdueState, final String[] targetTags, final Long + // distributionId, final String searchText, + // final Boolean noTagClicked + final Long pinnedDistId, final FilterParams filterParams) { final long size; if (managementUIState.getTargetTableFilters().getTargetFilterQuery().isPresent()) { size = targetManagement.countTargetByTargetFilterQuery( managementUIState.getTargetTableFilters().getTargetFilterQuery().get()); - } else if (!anyFilterSelected(status, pinnedDistId, noTagClicked, targetTags, searchText)) { + } else if (!anyFilterSelected(filterParams.getFilterByStatus(), pinnedDistId, + filterParams.getSelectTargetWithNoTag(), filterParams.getFilterByTagNames(), + filterParams.getFilterBySearchText())) { size = totalTargetsCount; } else { - size = targetManagement.countTargetByFilters(status, overdueState, searchText, distributionId, noTagClicked, - targetTags); + size = targetManagement.countTargetByFilters(filterParams.getFilterByStatus(), + filterParams.getOverdueState(), filterParams.getFilterBySearchText(), + filterParams.getFilterByDistributionId(), filterParams.getSelectTargetWithNoTag(), + filterParams.getFilterByTagNames()); } return size; } From e8d301a0a97c64be261f281ed0429510904883bd Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Thu, 22 Sep 2016 16:26:58 +0200 Subject: [PATCH 07/17] Fix license header. Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../java/org/eclipse/hawkbit/repository/FilterParams.java | 8 ++++++++ .../hawkbit/repository/jpa/TimestampCalculator.java | 8 ++++++++ .../repository/jpa/rsql/VirtualPropertyLookup.java | 2 +- .../repository/jpa/rsql/VirtualPropertyResolver.java | 2 +- .../repository/jpa/rsql/VirtualPropertyResolverTest.java | 2 +- 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java index 2c50ce41b..e9f5e0150 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java @@ -1,3 +1,11 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ package org.eclipse.hawkbit.repository; import java.util.Collection; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java index 038ab263d..e35980230 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java @@ -1,3 +1,11 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ package org.eclipse.hawkbit.repository.jpa; import java.time.Duration; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java index 95e34a89f..16a3c47e3 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016 Bosch Software Innovations GmbH and others. + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java index c1e87c43a..4fe734cfa 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016 Bosch Software Innovations GmbH and others. + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index e21ec7bcd..ee81985de 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016 Bosch Software Innovations GmbH and others. + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 From 52576a44897bcdfb774f214f2733f0f74c50d579 Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Fri, 23 Sep 2016 08:36:10 +0200 Subject: [PATCH 08/17] Add comment for public constructor. Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../hawkbit/repository/FilterParams.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java index e9f5e0150..eef479831 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java @@ -28,6 +28,25 @@ public class FilterParams { String[] filterByTagNames; Long filterByDistributionId; + /** + * Constructor. + * + * @param filterByDistributionId + * if set, a filter is added for the given + * {@link DistributionSet#getId()} + * @param filterByStatus + * if set, a filter is added for target states included by the + * collection + * @param overdueState + * if set, a filter is added for overdued devices + * @param filterBySearchText + * if set, a filter is added for the given search text + * @param selectTargetWithNoTag + * if set, tag-filtering is enabled + * @param filterByTagNames + * if tag-filtering is enabled, a filter is added for the given + * tag-names + */ public FilterParams(Long filterByDistributionId, Collection filterByStatus, Boolean overdueState, String filterBySearchText, Boolean selectTargetWithNoTag, String... filterByTagNames) { From ab7c2d6a61132d4abc0dd76a39d3febb34858ab4 Mon Sep 17 00:00:00 2001 From: "Marcel Mager (INST-IOT/ESB)" Date: Fri, 23 Sep 2016 09:57:23 +0200 Subject: [PATCH 09/17] Fix code smells. Signed-off-by: Marcel Mager (INST-IOT/ESB) --- .../repository/jpa/TimestampCalculator.java | 10 ++-- .../repository/jpa/rsql/RSQLUtility.java | 6 +-- .../jpa/rsql/VirtualPropertyLookup.java | 2 +- .../jpa/rsql/VirtualPropertyResolverTest.java | 10 ++-- .../management/event/ManagementUIEvent.java | 49 +++++++++++++------ .../management/event/TargetFilterEvent.java | 28 +++++++---- .../targettable/TargetBeanQuery.java | 2 +- 7 files changed, 69 insertions(+), 38 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java index e35980230..071da214d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java @@ -17,6 +17,12 @@ import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.springframework.stereotype.Service; +/** + * Service that calculates non-persistent timestamps , e.g. the point a time a + * target is declared as overdue.
    + * Therefore tenant specific configuration may be considered. + * + */ @Service public class TimestampCalculator { @@ -33,10 +39,8 @@ public class TimestampCalculator { * value */ public long calculateOverdueTimestamp() { - long overdueTs = Instant.now().toEpochMilli() // - - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() // + return Instant.now().toEpochMilli() - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis(); - return overdueTs; } private Duration getDurationForKey(TenantConfigurationKey key) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index a95172636..10bc24e8a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -446,8 +446,8 @@ public final class RSQLUtility { final Object transformedValue = transformedValues.get(0); final String value; - if (virtualPropertyLookup != null) { // if lookup is available, - // replace macros ... + // if lookup is available, replace macros ... + if (virtualPropertyLookup != null) { value = substitutor.replace(values.get(0)); } else { value = values.get(0); @@ -596,7 +596,7 @@ public final class RSQLUtility { /** * Adapts the VirtualPropertyLookup to StrLookup. */ - final static class StrLookupAdapter extends StrLookup { + static final class StrLookupAdapter extends StrLookup { private VirtualPropertyLookup virtualPropertyLookup; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java index 16a3c47e3..a67064261 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java @@ -24,5 +24,5 @@ public interface VirtualPropertyLookup { * @return the value for the placeholder; may be null if no * value could be found for the given placeholder; */ - public String lookup(String placeholder); + String lookup(String placeholder); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index ee81985de..d3c069e31 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -76,7 +76,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertFalse(resolvedPlaceholders.contains(placeholder)); + assertFalse("NOW_TS has to be resolved!", resolvedPlaceholders.contains(placeholder)); } @Test @@ -86,7 +86,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertFalse(resolvedPlaceholders.contains(placeholder)); + assertFalse("OVERDUE_TS has to be resolved!", resolvedPlaceholders.contains(placeholder)); } @Test @@ -96,7 +96,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertFalse(resolvedPlaceholders.contains(placeholder)); + assertFalse("overdue_ts has to be resolved!", resolvedPlaceholders.contains(placeholder)); } @Test @@ -106,7 +106,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertTrue(resolvedPlaceholders.contains(placeholder)); + assertTrue("unknown should not be resolved!", resolvedPlaceholders.contains(placeholder)); } @Test @@ -117,6 +117,6 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + escaptedPlaceholder; String resolvedPlaceholders = substitutor.replace(testString); - assertTrue(resolvedPlaceholders.contains(placeholder)); + assertTrue("Escaped OVERDUE_TS should not be resolved!", resolvedPlaceholders.contains(placeholder)); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java index 2c6c83e8a..f482cd795 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java @@ -14,22 +14,39 @@ package org.eclipse.hawkbit.ui.management.event; * */ public enum ManagementUIEvent { - SHOW_COUNT_MESSAGE, // - UPDATE_COUNT, // - UPDATE_FILTERCOUNT_MESSAGE, // - HIDE_TARGET_TAG_LAYOUT, // - SHOW_TARGET_TAG_LAYOUT, // - HIDE_DISTRIBUTION_TAG_LAYOUT, // - SHOW_DISTRIBUTION_TAG_LAYOUT, // - MAX_ACTION_HISTORY, // - MIN_ACTION_HISTORY, // - CLOSE_SAVE_ACTIONS_WINDOW, // - UNASSIGN_TARGET_TAG, // - UNASSIGN_DISTRIBUTION_TAG, // - ASSIGN_TARGET_TAG, // - ASSIGN_DISTRIBUTION_TAG, // - TARGET_TABLE_FILTER, // - RESET_SIMPLE_FILTERS, // + // + SHOW_COUNT_MESSAGE, + // + UPDATE_COUNT, + // + UPDATE_FILTERCOUNT_MESSAGE, + // + HIDE_TARGET_TAG_LAYOUT, + // + SHOW_TARGET_TAG_LAYOUT, + // + HIDE_DISTRIBUTION_TAG_LAYOUT, + // + SHOW_DISTRIBUTION_TAG_LAYOUT, + // + MAX_ACTION_HISTORY, + // + MIN_ACTION_HISTORY, + // + CLOSE_SAVE_ACTIONS_WINDOW, + // + UNASSIGN_TARGET_TAG, + // + UNASSIGN_DISTRIBUTION_TAG, + // + ASSIGN_TARGET_TAG, + // + ASSIGN_DISTRIBUTION_TAG, + // + TARGET_TABLE_FILTER, + // + RESET_SIMPLE_FILTERS, + // RESET_TARGET_FILTER_QUERY } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java index 834f06031..4ab36de32 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java @@ -14,14 +14,24 @@ package org.eclipse.hawkbit.ui.management.event; * */ public enum TargetFilterEvent { - FILTER_BY_TEXT, // - FILTER_BY_TAG, // - REMOVE_FILTER_BY_TEXT, // - REMOVE_FILTER_BY_TAG, // - FILTER_BY_STATUS, // - FILTER_BY_DISTRIBUTION, // - REMOVE_FILTER_BY_STATUS, // - REMOVE_FILTER_BY_DISTRIBUTION, // - FILTER_BY_TARGET_FILTER_QUERY, // + // + FILTER_BY_TEXT, + // + FILTER_BY_TAG, + // + REMOVE_FILTER_BY_TEXT, + // + REMOVE_FILTER_BY_TAG, + // + FILTER_BY_STATUS, + // + FILTER_BY_DISTRIBUTION, + // + REMOVE_FILTER_BY_STATUS, + // + REMOVE_FILTER_BY_DISTRIBUTION, + // + FILTER_BY_TARGET_FILTER_QUERY, + // REMOVE_FILTER_BY_TARGET_FILTER_QUERY } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index ee1f59159..ca75fc578 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -52,7 +52,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { private Sort sort = new Sort(TARGET_TABLE_CREATE_AT_SORT_ORDER, "createdAt"); private transient Collection status = null; - private transient Boolean overdueState = null; + private transient Boolean overdueState; private String[] targetTags = null; private Long distributionId = null; private String searchText = null; From 405a0aa12575ddf655188f061bfd2dab22a256be Mon Sep 17 00:00:00 2001 From: Dominik Herbst Date: Tue, 27 Sep 2016 11:10:52 +0200 Subject: [PATCH 10/17] Fixed visibility and sonar issues Signed-off-by: Dominik Herbst --- .../hawkbit/repository/FilterParams.java | 18 ++++++++++++------ .../repository/jpa/rsql/RSQLUtility.java | 19 +++++++++---------- .../management/targettable/TargetTable.java | 11 +++++++++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java index eef479831..33bafaa3c 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/FilterParams.java @@ -21,12 +21,12 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; */ public class FilterParams { - Collection filterByStatus; - Boolean overdueState; - String filterBySearchText; - Boolean selectTargetWithNoTag; - String[] filterByTagNames; - Long filterByDistributionId; + private Collection filterByStatus; + private Boolean overdueState; + private String filterBySearchText; + private Boolean selectTargetWithNoTag; + private String[] filterByTagNames; + private Long filterByDistributionId; /** * Constructor. @@ -72,6 +72,7 @@ public class FilterParams { * Sets {@link DistributionSet#getId()} to filter the result. * * @param filterByDistributionId + * the distribution set id */ public void setFilterByDistributionId(Long filterByDistributionId) { this.filterByDistributionId = filterByDistributionId; @@ -91,6 +92,7 @@ public class FilterParams { * Sets the collection of target states to filter for. * * @param filterByStatus + * collection of target update status */ public void setFilterByStatus(Collection filterByStatus) { this.filterByStatus = filterByStatus; @@ -113,6 +115,7 @@ public class FilterParams { * overdue filter is activated. * * @param overdueState + * if the overdue filter should be activates */ public void setOverdueState(Boolean overdueState) { this.overdueState = overdueState; @@ -133,6 +136,7 @@ public class FilterParams { * Sets the search text to filter for. * * @param filterBySearchText + * search text */ public void setFilterBySearchText(String filterBySearchText) { this.filterBySearchText = filterBySearchText; @@ -152,6 +156,7 @@ public class FilterParams { * Sets the flag indicating if tagging filter is used. * * @param selectTargetWithNoTag + * should the tagging filter be used? */ public void setSelectTargetWithNoTag(Boolean selectTargetWithNoTag) { this.selectTargetWithNoTag = selectTargetWithNoTag; @@ -171,6 +176,7 @@ public class FilterParams { * Sets the tags that are used to filter for. * * @param filterByTagNames + * array of tag names */ public void setFilterByTagNames(String[] filterByTagNames) { this.filterByTagNames = filterByTagNames; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index 10bc24e8a..bfb7e5cf1 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -187,7 +187,6 @@ public final class RSQLUtility { private final Root root; private final CriteriaBuilder cb; private final Class enumType; - private final VirtualPropertyLookup virtualPropertyLookup; private final StrSubstitutor substitutor; private final SimpleTypeConverter simpleTypeConverter; @@ -197,10 +196,10 @@ public final class RSQLUtility { this.root = root; this.cb = cb; this.enumType = enumType; - this.virtualPropertyLookup = virtualPropertyLookup; - this.substitutor = new StrSubstitutor(new StrLookupAdapter(virtualPropertyLookup), - StrSubstitutor.DEFAULT_PREFIX, - StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); + this.substitutor = (virtualPropertyLookup != null) + ? new StrSubstitutor(new StrLookupAdapter(virtualPropertyLookup), StrSubstitutor.DEFAULT_PREFIX, + StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE) + : null; simpleTypeConverter = new SimpleTypeConverter(); } @@ -222,7 +221,7 @@ public final class RSQLUtility { return toSingleList(cb.conjunction()); } - private List toSingleList(final Predicate predicate) { + private static List toSingleList(final Predicate predicate) { return Collections.singletonList(predicate); } @@ -419,7 +418,7 @@ public final class RSQLUtility { // Exception squid:S2095 - see // https://jira.sonarsource.com/browse/SONARJAVA-1478 @SuppressWarnings({ "rawtypes", "unchecked", "squid:S2095" }) - private Object transformEnumValue(final ComparisonNode node, final String value, + private static Object transformEnumValue(final ComparisonNode node, final String value, final Class javaType) { final Class tmpEnumType = (Class) javaType; try { @@ -447,7 +446,7 @@ public final class RSQLUtility { final String value; // if lookup is available, replace macros ... - if (virtualPropertyLookup != null) { + if (substitutor != null) { value = substitutor.replace(values.get(0)); } else { value = values.get(0); @@ -568,12 +567,12 @@ public final class RSQLUtility { return cb.notEqual(fieldPath, transformedValue); } - private String escapeValueToSQL(final String transformedValue) { + private static String escapeValueToSQL(final String transformedValue) { return transformedValue.replace("%", "\\%").replace(LIKE_WILDCARD, '%'); } @SuppressWarnings("unchecked") - private Path pathOfString(final Path path) { + private static Path pathOfString(final Path path) { return (Path) path; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java index 5d1e6a46e..ed8f389df 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java @@ -8,7 +8,14 @@ */ package org.eclipse.hawkbit.ui.management.targettable; -import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.*; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_DISTRIBUTION; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_TAG; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_TARGET_FILTER_QUERY; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.FILTER_BY_TEXT; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_DISTRIBUTION; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_TAG; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_TARGET_FILTER_QUERY; +import static org.eclipse.hawkbit.ui.management.event.TargetFilterEvent.REMOVE_FILTER_BY_TEXT; import java.util.ArrayList; import java.util.Collection; @@ -416,7 +423,7 @@ public class TargetTable extends AbstractTable { /** * Add listener to pin. * - * @param pinBtn + * @param event * as event */ private void addPinClickListener(final ClickEvent event) { From 5874d1c60fc01bcfae1c58e22023ca00a9d4ce5d Mon Sep 17 00:00:00 2001 From: Dominik Herbst Date: Tue, 27 Sep 2016 11:56:54 +0200 Subject: [PATCH 11/17] VirtualPropertyResolver extends now StrLookup to avoid an additonal wrapper in RSQLUtility Signed-off-by: Dominik Herbst --- .../repository/jpa/rsql/RSQLUtility.java | 27 ++----------------- .../jpa/rsql/VirtualPropertyResolver.java | 3 ++- .../jpa/rsql/VirtualPropertyResolverTest.java | 2 +- 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index bfb7e5cf1..f3e2ce50d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -196,8 +196,8 @@ public final class RSQLUtility { this.root = root; this.cb = cb; this.enumType = enumType; - this.substitutor = (virtualPropertyLookup != null) - ? new StrSubstitutor(new StrLookupAdapter(virtualPropertyLookup), StrSubstitutor.DEFAULT_PREFIX, + this.substitutor = (virtualPropertyLookup != null && virtualPropertyLookup instanceof StrLookup) + ? new StrSubstitutor((StrLookup)virtualPropertyLookup, StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE) : null; simpleTypeConverter = new SimpleTypeConverter(); @@ -592,27 +592,4 @@ public final class RSQLUtility { } - /** - * Adapts the VirtualPropertyLookup to StrLookup. - */ - static final class StrLookupAdapter extends StrLookup { - - private VirtualPropertyLookup virtualPropertyLookup; - - /** - * Constructor. - * - * @param virtualPropertyLookup - * the lookup to adapt. - */ - StrLookupAdapter(VirtualPropertyLookup virtualPropertyLookup) { - this.virtualPropertyLookup = virtualPropertyLookup; - } - - @Override - public String lookup(String key) { - return virtualPropertyLookup.lookup(key); - } - - } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java index 4fe734cfa..739874610 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql; import java.time.Instant; +import org.apache.commons.lang3.text.StrLookup; import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -41,7 +42,7 @@ import org.springframework.stereotype.Component; * */ @Component -public class VirtualPropertyResolver implements VirtualPropertyLookup { +public class VirtualPropertyResolver extends StrLookup implements VirtualPropertyLookup { @Autowired private TimestampCalculator timestampCalculator; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index d3c069e31..daa816f8e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -64,7 +64,7 @@ public class VirtualPropertyResolverTest { } }); - this.substitutor = new StrSubstitutor(new RSQLUtility.StrLookupAdapter(resolverUnderTest), + this.substitutor = new StrSubstitutor(resolverUnderTest, StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); } From b1d9930d9444b2fbf3228fd4703512d92b247abc Mon Sep 17 00:00:00 2001 From: Dominik Herbst Date: Wed, 28 Sep 2016 13:54:54 +0200 Subject: [PATCH 12/17] Optimized implementation of VirtualPropertyReplacer. Added auto configuration for VirtualPropertyResolver. Signed-off-by: Dominik Herbst --- .../JpaRepositoryAutoConfiguration.java | 16 +++++++++- .../rsql/VirtualPropertyReplacer.java} | 16 +++++----- .../repository/jpa/TimestampCalculator.java | 4 +-- .../TenantConfigurationManagementHolder.java | 0 .../jpa/rsql/VirtualPropertyResolver.java | 25 +++++++++++----- .../jpa/JpaDeploymentManagement.java | 6 ++-- .../jpa/JpaDistributionSetManagement.java | 10 +++---- .../jpa/JpaRolloutGroupManagement.java | 8 ++--- .../repository/jpa/JpaRolloutManagement.java | 6 ++-- .../repository/jpa/JpaSoftwareManagement.java | 10 +++---- .../repository/jpa/JpaTagManagement.java | 8 ++--- .../jpa/JpaTargetFilterQueryManagement.java | 6 ++-- .../repository/jpa/JpaTargetManagement.java | 18 ++++++------ .../repository/jpa/rsql/RSQLUtility.java | 29 +++++++++---------- .../repository/jpa/rsql/RSQLUtilityTest.java | 3 +- .../jpa/rsql/VirtualPropertyResolverTest.java | 1 + .../eclipse/hawkbit/TestConfiguration.java | 11 +++++++ .../FilterQueryValidation.java | 5 ++-- 18 files changed, 106 insertions(+), 76 deletions(-) rename hawkbit-repository/{hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java => hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyReplacer.java} (54%) rename hawkbit-repository/{hawkbit-repository-jpa => hawkbit-repository-core}/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java (94%) rename hawkbit-repository/{hawkbit-repository-jpa => hawkbit-repository-core}/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java (100%) rename hawkbit-repository/{hawkbit-repository-jpa => hawkbit-repository-core}/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java (75%) diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java index dd6ead86b..245e4d57a 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java @@ -9,12 +9,16 @@ package org.eclipse.hawkbit.autoconfigure.repository; import org.eclipse.hawkbit.EnableJpaRepository; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * Auto-Configuration for enabling the REST-Resources. + * Auto-Configuration for enabling JPA repository. * */ @Configuration @@ -22,4 +26,14 @@ import org.springframework.context.annotation.Import; @Import({ EnableJpaRepository.class }) public class JpaRepositoryAutoConfiguration { + /** + * + * @return returns a VirtualPropertyReplacer + */ + @Bean + @ConditionalOnMissingBean + public VirtualPropertyReplacer virtualPropertyReplacer() { + return new VirtualPropertyResolver(); + } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyReplacer.java similarity index 54% rename from hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyReplacer.java index a67064261..abdc671f7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyLookup.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyReplacer.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.jpa.rsql; +package org.eclipse.hawkbit.repository.rsql; /** * Implementations map a placeholder to the associated value. @@ -14,15 +14,15 @@ package org.eclipse.hawkbit.repository.jpa.rsql; * This is used in context of string replacement. */ @FunctionalInterface -public interface VirtualPropertyLookup { +public interface VirtualPropertyReplacer { /** - * Looks up a placeholder to the associated value. + * Looks up a placeholders and replaces them * - * @param placeholder - * the virtual property that should be resolved by a value - * @return the value for the placeholder; may be null if no - * value could be found for the given placeholder; + * @param input + * the input string in which virtual properties should be + * replaced + * @return the result of the replacement */ - String lookup(String placeholder); + String replace(String input); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java similarity index 94% rename from hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java rename to hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java index 071da214d..ea467b316 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java @@ -15,15 +15,13 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; -import org.springframework.stereotype.Service; /** - * Service that calculates non-persistent timestamps , e.g. the point a time a + * Calculates non-persistent timestamps , e.g. the point a time a * target is declared as overdue.
    * Therefore tenant specific configuration may be considered. * */ -@Service public class TimestampCalculator { /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java similarity index 100% rename from hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java rename to hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantConfigurationManagementHolder.java diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java similarity index 75% rename from hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java rename to hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java index 739874610..1e78d7f10 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java @@ -11,9 +11,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql; import java.time.Instant; import org.apache.commons.lang3.text.StrLookup; +import org.apache.commons.lang3.text.StrSubstitutor; import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; /** * Adds macro capabilities to RSQL expressions that are used to filter for @@ -24,8 +24,8 @@ import org.springframework.stereotype.Component; * time intervals).
    * Such a virtual property needs to be calculated on Java-side before it may be * used in a target filter query that is passed to the database. Therefore a - * placeholder is used in the RSQL expression that is expanded in the - * {@link RSQLUtility}. + * placeholder is used in the RSQL expression that is expanded when the RSQL is + * parsed *

    * A virtual property may either be a system value like the current date (aka * now_ts) or a value derived from (tenant-specific) system @@ -41,11 +41,11 @@ import org.springframework.stereotype.Component; * configuration. * */ -@Component -public class VirtualPropertyResolver extends StrLookup implements VirtualPropertyLookup { +public class VirtualPropertyResolver extends StrLookup implements VirtualPropertyReplacer { - @Autowired - private TimestampCalculator timestampCalculator; + private final TimestampCalculator timestampCalculator = new TimestampCalculator(); + + private StrSubstitutor substitutor; @Override public String lookup(String rhs) { @@ -59,6 +59,15 @@ public class VirtualPropertyResolver extends StrLookup implements Virtua return resolved; } + @Override + public String replace(String input) { + if (substitutor == null) { + substitutor = new StrSubstitutor(this, StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX, + StrSubstitutor.DEFAULT_ESCAPE); + } + return substitutor.replace(input); + } + TimestampCalculator getTimestampCalculator() { return timestampCalculator; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java index 1a7655096..6014e6802 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java @@ -54,7 +54,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; @@ -136,7 +136,7 @@ public class JpaDeploymentManagement implements DeploymentManagement { private SystemSecurityContext systemSecurityContext; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Override @Transactional(isolation = Isolation.READ_COMMITTED) @@ -609,7 +609,7 @@ public class JpaDeploymentManagement implements DeploymentManagement { } private Specification createSpecificationFor(final Target target, final String rsqlParam) { - final Specification spec = RSQLUtility.parse(rsqlParam, ActionFields.class, virtualPropertyLookup); + final Specification spec = RSQLUtility.parse(rsqlParam, ActionFields.class, virtualPropertyReplacer); return (root, query, cb) -> cb.and(spec.toPredicate(root, query, cb), cb.equal(root.get(JpaAction_.target), target)); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 7d719acbe..b9df4e1b0 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -42,7 +42,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata_; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; @@ -109,7 +109,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { private TenantAware tenantAware; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Override public DistributionSet findDistributionSetByIdWithDetails(final Long distid) { @@ -283,7 +283,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Override public Page findDistributionSetTypesAll(final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, - DistributionSetTypeFields.class, virtualPropertyLookup); + DistributionSetTypeFields.class, virtualPropertyReplacer); return convertDsTPage(distributionSetTypeRepository.findAll(spec, pageable)); } @@ -350,7 +350,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { final Boolean deleted) { final Specification spec = RSQLUtility.parse(rsqlParam, DistributionSetFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); final List> specList = new ArrayList<>(2); if (deleted != null) { @@ -562,7 +562,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, - DistributionSetMetadataFields.class, virtualPropertyLookup); + DistributionSetMetadataFields.class, virtualPropertyReplacer); return convertMdPage( distributionSetMetadataRepository diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java index 0453bf26b..382b8fab4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java @@ -33,7 +33,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; @@ -72,7 +72,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { private EntityManager entityManager; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Override public RolloutGroup findRolloutGroupById(final Long rolloutGroupId) { @@ -97,7 +97,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { final Pageable pageable) { final Specification specification = RSQLUtility.parse(rsqlParam, RolloutGroupFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return convertPage( rolloutGroupRepository @@ -151,7 +151,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { final Pageable pageable) { final Specification rsqlSpecification = RSQLUtility.parse(rsqlParam, TargetFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return convertTPage(targetRepository.findAll((root, query, criteriaBuilder) -> { final ListJoin rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java index ca5c8389d..3845a0c5a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java @@ -32,7 +32,7 @@ import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator; import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupConditionEvaluator; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.DistributionSet; @@ -116,7 +116,7 @@ public class JpaRolloutManagement implements RolloutManagement { private CacheWriteNotify cacheWriteNotify; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Autowired @Qualifier("asyncExecutor") @@ -155,7 +155,7 @@ public class JpaRolloutManagement implements RolloutManagement { public Page findAllWithDetailedStatusByPredicate(final String rsqlParam, final Pageable pageable) { final Specification specification = RSQLUtility.parse(rsqlParam, RolloutFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); final Page findAll = rolloutRepository.findAll(specification, pageable); setRolloutStatusDetails(findAll); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index fad743baf..f403ff38b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -45,7 +45,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; @@ -108,7 +108,7 @@ public class JpaSoftwareManagement implements SoftwareManagement { private ArtifactManagement artifactManagement; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Override @Modifying @@ -317,7 +317,7 @@ public class JpaSoftwareManagement implements SoftwareManagement { @Override public Page findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable); } @@ -326,7 +326,7 @@ public class JpaSoftwareManagement implements SoftwareManagement { public Page findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable); } @@ -612,7 +612,7 @@ public class JpaSoftwareManagement implements SoftwareManagement { final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, - SoftwareModuleMetadataFields.class, virtualPropertyLookup); + SoftwareModuleMetadataFields.class, virtualPropertyReplacer); return convertSmMdPage( softwareModuleMetadataRepository .findAll( diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java index fcc97729e..fd151b527 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java @@ -30,7 +30,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -76,7 +76,7 @@ public class JpaTagManagement implements TagManagement { private AfterTransactionCommitExecutor afterCommit; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Override public TargetTag findTargetTag(final String name) { @@ -151,7 +151,7 @@ public class JpaTagManagement implements TagManagement { @Override public Page findAllTargetTags(final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class, virtualPropertyLookup); + final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class, virtualPropertyReplacer); return convertTPage(targetTagRepository.findAll(spec, pageable), pageable); } @@ -285,7 +285,7 @@ public class JpaTagManagement implements TagManagement { @Override public Page findAllDistributionSetTags(final String rsqlParam, final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, TagFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return convertDsPage(distributionSetTagRepository.findAll(spec, pageable), pageable); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java index 39343d3a4..ed9ba5977 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java @@ -16,7 +16,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; @@ -46,7 +46,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme private TargetFilterQueryRepository targetFilterQueryRepository; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Override @Modifying @@ -115,7 +115,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme @Override public boolean verifyTargetFilterQuerySyntax(final String query) { - RSQLUtility.parse(query, TargetFields.class, virtualPropertyLookup); + RSQLUtility.parse(query, TargetFields.class, virtualPropertyReplacer); return true; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 878c70f04..75e883c83 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -42,7 +42,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyLookup; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.model.Target; @@ -105,7 +105,7 @@ public class JpaTargetManagement implements TargetManagement { private AfterTransactionCommitExecutor afterCommit; @Autowired - private VirtualPropertyLookup virtualPropertyLookup; + private VirtualPropertyReplacer virtualPropertyReplacer; @Override public Target findTargetByControllerID(final String controllerId) { @@ -158,13 +158,13 @@ public class JpaTargetManagement implements TargetManagement { @Override public Slice findTargetsAll(final TargetFilterQuery targetFilterQuery, final Pageable pageable) { return findTargetsBySpec( - RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyLookup), + RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyReplacer), pageable); } @Override public Page findTargetsAll(final String targetFilterQuery, final Pageable pageable) { - return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class, virtualPropertyLookup), + return findTargetsBySpec(RSQLUtility.parse(targetFilterQuery, TargetFields.class, virtualPropertyReplacer), pageable); } @@ -233,7 +233,7 @@ public class JpaTargetManagement implements TargetManagement { final Pageable pageReq) { final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return convertPage( targetRepository @@ -262,7 +262,7 @@ public class JpaTargetManagement implements TargetManagement { final Pageable pageable) { final Specification spec = RSQLUtility.parse(rsqlParam, TargetFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return convertPage( targetRepository @@ -566,7 +566,7 @@ public class JpaTargetManagement implements TargetManagement { final CriteriaQuery multiselect = query.multiselect(targetRoot.get(JpaTarget_.id), targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty)); - final Specification spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyLookup); + final Specification spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyReplacer); final Predicate[] specificationsForMultiSelect = specificationsToPredicate(Lists.newArrayList(spec), targetRoot, multiselect, cb); @@ -645,14 +645,14 @@ public class JpaTargetManagement implements TargetManagement { @Override public Long countTargetByTargetFilterQuery(final TargetFilterQuery targetFilterQuery) { final Specification specs = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return targetRepository.count(specs); } @Override public Long countTargetByTargetFilterQuery(final String targetFilterQuery) { final Specification specs = RSQLUtility.parse(targetFilterQuery, TargetFields.class, - virtualPropertyLookup); + virtualPropertyReplacer); return targetRepository.count(specs); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index f3e2ce50d..7565f464a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -26,11 +26,11 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.apache.commons.lang3.text.StrLookup; -import org.apache.commons.lang3.text.StrSubstitutor; import org.eclipse.hawkbit.repository.FieldNameProvider; import org.eclipse.hawkbit.repository.FieldValueConverter; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.SimpleTypeConverter; @@ -99,7 +99,7 @@ public final class RSQLUtility { * @param fieldNameProvider * the enum class type which implements the * {@link FieldNameProvider} - * @param virtualPropertyLookup + * @param virtualPropertyReplacer * holds the logic how the known macros have to be resolved; may * be null * @return an specification which can be used with JPA @@ -110,8 +110,8 @@ public final class RSQLUtility { * if the RSQL syntax is wrong */ public static & FieldNameProvider, T> Specification parse(final String rsql, - final Class fieldNameProvider, VirtualPropertyLookup virtualPropertyLookup) { - return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, virtualPropertyLookup); + final Class fieldNameProvider, VirtualPropertyReplacer virtualPropertyReplacer) { + return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, virtualPropertyReplacer); } /** @@ -142,13 +142,13 @@ public final class RSQLUtility { private final String rsql; private final Class enumType; - private final VirtualPropertyLookup virtualPropertyLookup; + private final VirtualPropertyReplacer virtualPropertyReplacer; private RSQLSpecification(final String rsql, final Class enumType, - VirtualPropertyLookup virtualPropertyLookup) { + VirtualPropertyReplacer virtualPropertyReplacer) { this.rsql = rsql; this.enumType = enumType; - this.virtualPropertyLookup = virtualPropertyLookup; + this.virtualPropertyReplacer = virtualPropertyReplacer; } @Override @@ -157,7 +157,7 @@ public final class RSQLUtility { final Node rootNode = parseRsql(rsql); final JpqQueryRSQLVisitor jpqQueryRSQLVisitor = new JpqQueryRSQLVisitor<>(root, cb, enumType, - virtualPropertyLookup); + virtualPropertyReplacer); final List accept = rootNode., String> accept(jpqQueryRSQLVisitor); if (accept != null && !accept.isEmpty()) { @@ -187,19 +187,16 @@ public final class RSQLUtility { private final Root root; private final CriteriaBuilder cb; private final Class enumType; - private final StrSubstitutor substitutor; + private final VirtualPropertyReplacer virtualPropertyReplacer; private final SimpleTypeConverter simpleTypeConverter; private JpqQueryRSQLVisitor(final Root root, final CriteriaBuilder cb, final Class enumType, - VirtualPropertyLookup virtualPropertyLookup) { + VirtualPropertyReplacer virtualPropertyReplacer) { this.root = root; this.cb = cb; this.enumType = enumType; - this.substitutor = (virtualPropertyLookup != null && virtualPropertyLookup instanceof StrLookup) - ? new StrSubstitutor((StrLookup)virtualPropertyLookup, StrSubstitutor.DEFAULT_PREFIX, - StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE) - : null; + this.virtualPropertyReplacer = virtualPropertyReplacer; simpleTypeConverter = new SimpleTypeConverter(); } @@ -446,8 +443,8 @@ public final class RSQLUtility { final String value; // if lookup is available, replace macros ... - if (substitutor != null) { - value = substitutor.replace(values.get(0)); + if (virtualPropertyReplacer != null) { + value = virtualPropertyReplacer.replace(values.get(0)); } else { value = values.get(0); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index 1e73bbe24..d72f92f11 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldExc import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.junit.Test; import org.junit.runner.RunWith; @@ -321,7 +322,7 @@ public class RSQLUtilityTest { eq(overduePropPlaceholder)); } - public VirtualPropertyLookup setupMacroLookup() { + public VirtualPropertyReplacer setupMacroLookup() { when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class)) .thenReturn(TEST_POLLING_TIME_INTERVAL); when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index daa816f8e..a519c8188 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -9,6 +9,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql; import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import java.time.Instant; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java index 499925540..716236d3a 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java @@ -15,6 +15,8 @@ import org.eclipse.hawkbit.cache.CacheConstants; import org.eclipse.hawkbit.cache.TenancyCacheManager; import org.eclipse.hawkbit.cache.TenantAwareCacheManager; import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; +import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver; +import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.test.util.JpaTestRepositoryManagement; import org.eclipse.hawkbit.repository.test.util.TestRepositoryManagement; import org.eclipse.hawkbit.repository.test.util.TestdataFactory; @@ -120,4 +122,13 @@ public class TestConfiguration implements AsyncConfigurer { return new SimpleAsyncUncaughtExceptionHandler(); } + /** + * + * @return returns a VirtualPropertyReplacer + */ + @Bean + public VirtualPropertyReplacer virtualPropertyReplacer() { + return new VirtualPropertyResolver(); + } + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java index 6d1f1a7ab..869608990 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java @@ -43,9 +43,8 @@ public final class FilterQueryValidation { /** * method for get ExpectedTokens. * - * @param input - * @param entityManager - * @return + * @param input RSQL filter + * @return Validation result */ public static ValidationResult getExpectedTokens(final String input) { From 41955b76718fe62aa38fd88b67e85ffac84c24f1 Mon Sep 17 00:00:00 2001 From: Dominik Herbst Date: Tue, 4 Oct 2016 16:21:17 +0200 Subject: [PATCH 13/17] Changed VirtualPropertyResolver to accept TimestampCalculator in the constructor Signed-off-by: Dominik Herbst --- .../repository/JpaRepositoryAutoConfiguration.java | 3 ++- .../jpa/rsql/VirtualPropertyResolver.java | 13 ++++++++++++- .../hawkbit/repository/jpa/rsql/RSQLUtility.java | 6 ++---- .../repository/jpa/rsql/RSQLUtilityTest.java | 2 +- .../jpa/rsql/VirtualPropertyResolverTest.java | 2 +- .../java/org/eclipse/hawkbit/TestConfiguration.java | 3 ++- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java index 245e4d57a..05249f017 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java @@ -9,6 +9,7 @@ package org.eclipse.hawkbit.autoconfigure.repository; import org.eclipse.hawkbit.EnableJpaRepository; +import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -33,7 +34,7 @@ public class JpaRepositoryAutoConfiguration { @Bean @ConditionalOnMissingBean public VirtualPropertyReplacer virtualPropertyReplacer() { - return new VirtualPropertyResolver(); + return new VirtualPropertyResolver(new TimestampCalculator()); } } diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java index 1e78d7f10..e0f1483aa 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java @@ -43,10 +43,21 @@ import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; */ public class VirtualPropertyResolver extends StrLookup implements VirtualPropertyReplacer { - private final TimestampCalculator timestampCalculator = new TimestampCalculator(); + private final TimestampCalculator timestampCalculator; private StrSubstitutor substitutor; + /** + * Instantiates a new virtual property resolver with the given timestamp + * calculator + * + * @param timestampCalculator + * calculates timestamps + */ + public VirtualPropertyResolver(TimestampCalculator timestampCalculator) { + this.timestampCalculator = timestampCalculator; + } + @Override public String lookup(String rhs) { String resolved = null; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java index 7565f464a..38665db38 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtility.java @@ -441,12 +441,10 @@ public final class RSQLUtility { // methods. final Object transformedValue = transformedValues.get(0); - final String value; + String value = values.get(0); // if lookup is available, replace macros ... if (virtualPropertyReplacer != null) { - value = virtualPropertyReplacer.replace(values.get(0)); - } else { - value = values.get(0); + value = virtualPropertyReplacer.replace(value); } final List singleList = new ArrayList<>(); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index d72f92f11..b4270e732 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -50,7 +50,7 @@ import ru.yandex.qatools.allure.annotations.Stories; public class RSQLUtilityTest { @Spy - VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(); + VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(new TimestampCalculator()); @Mock TenantConfigurationManagement confMgmt; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index a519c8188..0deb88b53 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -36,7 +36,7 @@ import ru.yandex.qatools.allure.annotations.Stories; public class VirtualPropertyResolverTest { @Spy - VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(); + VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(new TimestampCalculator()); @Mock TenantConfigurationManagement confMgmt; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java index 716236d3a..ab2d38686 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java @@ -14,6 +14,7 @@ import java.util.concurrent.Executors; import org.eclipse.hawkbit.cache.CacheConstants; import org.eclipse.hawkbit.cache.TenancyCacheManager; import org.eclipse.hawkbit.cache.TenantAwareCacheManager; +import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; @@ -128,7 +129,7 @@ public class TestConfiguration implements AsyncConfigurer { */ @Bean public VirtualPropertyReplacer virtualPropertyReplacer() { - return new VirtualPropertyResolver(); + return new VirtualPropertyResolver(new TimestampCalculator()); } } From 89687952d3be151ba1d29f86771cbb59c57cf05c Mon Sep 17 00:00:00 2001 From: Dominik Herbst Date: Thu, 13 Oct 2016 08:29:01 +0200 Subject: [PATCH 14/17] Improved code readability. Signed-off-by: Dominik Herbst --- .../repository/jpa/JpaTargetManagement.java | 12 ++++++--- .../repository/jpa/rsql/RSQLUtilityTest.java | 12 ++++----- .../jpa/rsql/VirtualPropertyResolverTest.java | 25 ++++++++++--------- .../targettable/TargetBeanQuery.java | 5 +--- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 75e883c83..5eddbee0d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -27,6 +27,7 @@ import javax.persistence.criteria.Order; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import org.apache.commons.lang3.StringUtils; import org.eclipse.hawkbit.repository.FilterParams; import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetManagement; @@ -68,7 +69,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; -import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.eventbus.EventBus; @@ -315,17 +315,21 @@ public class JpaTargetManagement implements TargetManagement { TargetSpecifications .hasInstalledOrAssignedDistributionSet(filterParams.getFilterByDistributionId())); } - if (!Strings.isNullOrEmpty(filterParams.getFilterBySearchText())) { + if (StringUtils.isNotEmpty(filterParams.getFilterBySearchText())) { specList.add(TargetSpecifications.likeNameOrDescriptionOrIp(filterParams.getFilterBySearchText())); } - if (filterParams.getSelectTargetWithNoTag() != null && (filterParams.getSelectTargetWithNoTag() - || (filterParams.getFilterByTagNames() != null && filterParams.getFilterByTagNames().length > 0))) { + if (isHasTagsFilterActive(filterParams)) { specList.add(TargetSpecifications.hasTags(filterParams.getFilterByTagNames(), filterParams.getSelectTargetWithNoTag())); } return specList; } + private static boolean isHasTagsFilterActive(final FilterParams filterParams) { + return filterParams.getSelectTargetWithNoTag() != null && (filterParams.getSelectTargetWithNoTag() + || (filterParams.getFilterByTagNames() != null && filterParams.getFilterByTagNames().length > 0)); + } + private Slice findByCriteriaAPI(final Pageable pageable, final List> specList) { if (specList == null || specList.isEmpty()) { return convertPage(criteriaNoCountDao.findAll(pageable, JpaTarget.class), pageable); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index b4270e732..20f5305c6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -50,13 +50,13 @@ import ru.yandex.qatools.allure.annotations.Stories; public class RSQLUtilityTest { @Spy - VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(new TimestampCalculator()); + private VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(new TimestampCalculator()); @Mock - TenantConfigurationManagement confMgmt; + private TenantConfigurationManagement confMgmt; @Mock - TimestampCalculator timestampCalculator; + private TimestampCalculator timestampCalculator; @Mock private Root baseSoftwareModuleRootMock; @@ -287,11 +287,11 @@ public class RSQLUtilityTest { .thenReturn(mock(Predicate.class)); // test - Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) + RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); - // verfication - verify(macroResolver, times(1)).lookup(overdueProp); + // verification + verify(macroResolver).lookup(overdueProp); // the macro is already replaced when passed to #lessThanOrEqualTo -> the method is never invoked with the // placeholder: verify(criteriaBuilderMock, never()).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index 0deb88b53..d37a2d1ee 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -9,9 +9,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql; import static org.junit.Assert.*; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; - +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import java.time.Instant; import org.apache.commons.lang3.text.StrSubstitutor; @@ -19,6 +19,7 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,14 +37,14 @@ import ru.yandex.qatools.allure.annotations.Stories; public class VirtualPropertyResolverTest { @Spy - VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(new TimestampCalculator()); + private VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(new TimestampCalculator()); @Mock - TenantConfigurationManagement confMgmt; + private TenantConfigurationManagement confMgmt; - StrSubstitutor substitutor; + private StrSubstitutor substitutor; - Long nowTestTime; + private Long nowTestTime; private static final TenantConfigurationValue TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue . builder().value("00:05:00").build(); @@ -65,7 +66,7 @@ public class VirtualPropertyResolverTest { } }); - this.substitutor = new StrSubstitutor(resolverUnderTest, + substitutor = new StrSubstitutor(resolverUnderTest, StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); } @@ -77,7 +78,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertFalse("NOW_TS has to be resolved!", resolvedPlaceholders.contains(placeholder)); + assertThat("NOW_TS has to be resolved!", resolvedPlaceholders, not(containsString(placeholder))); } @Test @@ -87,7 +88,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertFalse("OVERDUE_TS has to be resolved!", resolvedPlaceholders.contains(placeholder)); + assertThat("OVERDUE_TS has to be resolved!", resolvedPlaceholders, not(containsString(placeholder))); } @Test @@ -97,7 +98,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertFalse("overdue_ts has to be resolved!", resolvedPlaceholders.contains(placeholder)); + assertThat("overdue_ts has to be resolved!", resolvedPlaceholders, not(containsString(placeholder))); } @Test @@ -107,7 +108,7 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + placeholder; String resolvedPlaceholders = substitutor.replace(testString); - assertTrue("unknown should not be resolved!", resolvedPlaceholders.contains(placeholder)); + assertThat("unknown should not be resolved!", resolvedPlaceholders, containsString(placeholder)); } @Test @@ -118,6 +119,6 @@ public class VirtualPropertyResolverTest { String testString = "lhs=lt=" + escaptedPlaceholder; String resolvedPlaceholders = substitutor.replace(testString); - assertTrue("Escaped OVERDUE_TS should not be resolved!", resolvedPlaceholders.contains(placeholder)); + assertThat("Escaped OVERDUE_TS should not be resolved!", resolvedPlaceholders, containsString(placeholder)); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index ca75fc578..6a35b1c6f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -173,10 +173,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { } private Boolean isOverdueFilterEnabled() { - if (Boolean.TRUE.equals(overdueState)) { - return Boolean.TRUE; - } - return Boolean.FALSE; + return Boolean.TRUE.equals(overdueState); } @Override From 36656826f8a27f8ceb7dc6365f635883d0282302 Mon Sep 17 00:00:00 2001 From: Dominic Schabel Date: Thu, 13 Oct 2016 17:22:53 +0200 Subject: [PATCH 15/17] Fixed review comment: Don't use "Booleans.countTrue(...)" Signed-off-by: Dominic Schabel --- .../targettable/TargetBeanQuery.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index 6a35b1c6f..537d5427b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -8,10 +8,12 @@ */ package org.eclipse.hawkbit.ui.management.targettable; +import static com.google.common.base.Strings.isNullOrEmpty; import static org.apache.commons.lang3.ArrayUtils.isEmpty; import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.isNotNullOrEmpty; import static org.eclipse.hawkbit.ui.utils.SPUIDefinitions.TARGET_TABLE_CREATE_AT_SORT_ORDER; -import static org.springframework.data.domain.Sort.Direction.*; +import static org.springframework.data.domain.Sort.Direction.ASC; +import static org.springframework.data.domain.Sort.Direction.DESC; import java.util.ArrayList; import java.util.Collection; @@ -40,7 +42,6 @@ import org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery; import org.vaadin.addons.lazyquerycontainer.QueryDefinition; import com.google.common.base.Strings; -import com.google.common.primitives.Booleans; /** * Simple implementation of generics bean query which dynamically loads a batch @@ -120,7 +121,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { } else if (null != targetFilterQuery) { targetBeans = getTargetManagement().findTargetsAll(targetFilterQuery, new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort)); - } else if (!anyFilterSelected()) { + } else if (!isAnyFilterSelected()) { targetBeans = getTargetManagement().findTargetsAll( new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort)); } else { @@ -172,7 +173,7 @@ public class TargetBeanQuery extends AbstractBeanQuery { return true; } - private Boolean isOverdueFilterEnabled() { + private boolean isOverdueFilterEnabled() { return Boolean.TRUE.equals(overdueState); } @@ -182,22 +183,13 @@ public class TargetBeanQuery extends AbstractBeanQuery { // CRUD operations on Target will be done through repository methods } - private Boolean anyFilterSelected() { - int enabledFiltersCount = Booleans.countTrue(status != null, distributionId != null, - !Strings.isNullOrEmpty(searchText), isTagSelected(), isOverdueFilterEnabled()); - if (enabledFiltersCount == 0) { - return false; - } - return true; - } - @Override public int size() { final long totSize = getTargetManagement().countTargetsAll(); long size; if (null != targetFilterQuery) { size = getTargetManagement().countTargetByTargetFilterQuery(targetFilterQuery); - } else if (!anyFilterSelected()) { + } else if (!isAnyFilterSelected()) { size = totSize; } else { size = getTargetManagement().countTargetByFilters(status, overdueState, searchText, distributionId, @@ -216,6 +208,11 @@ public class TargetBeanQuery extends AbstractBeanQuery { return (int) size; } + private boolean isAnyFilterSelected() { + final boolean isFilterSelected = isTagSelected() || isOverdueFilterEnabled(); + return isFilterSelected || status != null || distributionId != null || !isNullOrEmpty(searchText); + } + private TargetManagement getTargetManagement() { if (targetManagement == null) { targetManagement = SpringContextHelper.getBean(TargetManagement.class); From d81619a1a07d55c834f0594edb07a81c955c0680 Mon Sep 17 00:00:00 2001 From: Dominik Herbst Date: Fri, 14 Oct 2016 10:32:10 +0200 Subject: [PATCH 16/17] Refactored TimestampCalculator to be static and adjusted tests using PowerMock. Signed-off-by: Dominik Herbst --- .../JpaRepositoryAutoConfiguration.java | 3 +-- .../repository/jpa/TimestampCalculator.java | 10 +++---- .../jpa/rsql/VirtualPropertyResolver.java | 23 +++++----------- .../hawkbit-repository-jpa/pom.xml | 10 +++++++ .../repository/jpa/JpaTargetManagement.java | 2 +- .../repository/jpa/rsql/RSQLUtilityTest.java | 26 ++++++++----------- .../jpa/rsql/VirtualPropertyResolverTest.java | 18 ++++++------- .../eclipse/hawkbit/TestConfiguration.java | 3 +-- pom.xml | 14 +++++++++- 9 files changed, 57 insertions(+), 52 deletions(-) diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java index 05249f017..245e4d57a 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/repository/JpaRepositoryAutoConfiguration.java @@ -9,7 +9,6 @@ package org.eclipse.hawkbit.autoconfigure.repository; import org.eclipse.hawkbit.EnableJpaRepository; -import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -34,7 +33,7 @@ public class JpaRepositoryAutoConfiguration { @Bean @ConditionalOnMissingBean public VirtualPropertyReplacer virtualPropertyReplacer() { - return new VirtualPropertyResolver(new TimestampCalculator()); + return new VirtualPropertyResolver(); } } diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java index ea467b316..303c9ea3a 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java @@ -22,7 +22,7 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; * Therefore tenant specific configuration may be considered. * */ -public class TimestampCalculator { +public final class TimestampCalculator { /** * Calculates the overdue timestamp (overdue_ts) based on the @@ -36,20 +36,20 @@ public class TimestampCalculator { * @return overdue_ts in milliseconds since Unix epoch as long * value */ - public long calculateOverdueTimestamp() { + public static long calculateOverdueTimestamp() { return Instant.now().toEpochMilli() - getDurationForKey(TenantConfigurationKey.POLLING_TIME_INTERVAL).toMillis() - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis(); } - private Duration getDurationForKey(TenantConfigurationKey key) { + private static Duration getDurationForKey(TenantConfigurationKey key) { return DurationHelper.formattedStringToDuration(getRawStringForKey(key)); } - private String getRawStringForKey(TenantConfigurationKey key) { + private static String getRawStringForKey(TenantConfigurationKey key) { return getTenantConfigurationManagement().getConfigurationValue(key, String.class).getValue(); } - protected TenantConfigurationManagement getTenantConfigurationManagement() { + public static TenantConfigurationManagement getTenantConfigurationManagement() { return TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement(); } } diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java index e0f1483aa..14f23b5be 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolver.java @@ -8,12 +8,17 @@ */ package org.eclipse.hawkbit.repository.jpa.rsql; +import java.time.Duration; import java.time.Instant; import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrSubstitutor; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; +import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; +import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; /** * Adds macro capabilities to RSQL expressions that are used to filter for @@ -43,21 +48,8 @@ import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; */ public class VirtualPropertyResolver extends StrLookup implements VirtualPropertyReplacer { - private final TimestampCalculator timestampCalculator; - private StrSubstitutor substitutor; - /** - * Instantiates a new virtual property resolver with the given timestamp - * calculator - * - * @param timestampCalculator - * calculates timestamps - */ - public VirtualPropertyResolver(TimestampCalculator timestampCalculator) { - this.timestampCalculator = timestampCalculator; - } - @Override public String lookup(String rhs) { String resolved = null; @@ -65,7 +57,7 @@ public class VirtualPropertyResolver extends StrLookup implements Virtua if ("now_ts".equalsIgnoreCase(rhs)) { resolved = String.valueOf(Instant.now().toEpochMilli()); } else if ("overdue_ts".equalsIgnoreCase(rhs)) { - resolved = String.valueOf(getTimestampCalculator().calculateOverdueTimestamp()); + resolved = String.valueOf(TimestampCalculator.calculateOverdueTimestamp()); } return resolved; } @@ -79,7 +71,4 @@ public class VirtualPropertyResolver extends StrLookup implements Virtua return substitutor.replace(input); } - TimestampCalculator getTimestampCalculator() { - return timestampCalculator; - } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/pom.xml b/hawkbit-repository/hawkbit-repository-jpa/pom.xml index 9f7a0bbb7..44f74e97c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/pom.xml +++ b/hawkbit-repository/hawkbit-repository-jpa/pom.xml @@ -141,6 +141,16 @@ fest-assert test + + org.powermock + powermock-module-junit4 + test + + + org.powermock + powermock-api-mockito + test + diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 9a412f9aa..0240f8458 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -309,7 +309,7 @@ public class JpaTargetManagement implements TargetManagement { } if (filterParams.getOverdueState() != null) { specList.add( - TargetSpecifications.isOverdue(new TimestampCalculator().calculateOverdueTimestamp())); + TargetSpecifications.isOverdue(TimestampCalculator.calculateOverdueTimestamp())); } if (filterParams.getFilterByDistributionId() != null) { specList.add( diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index 20f5305c6..db5f04c8a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql; import static org.junit.Assert.fail; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; +import static org.powermock.api.mockito.PowerMockito.mockStatic; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -36,28 +37,27 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; -import org.mockito.runners.MockitoJUnitRunner; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; -@RunWith(MockitoJUnitRunner.class) +@RunWith(PowerMockRunner.class) @Features("Component Tests - Repository") @Stories("RSQL search utility") +@PrepareForTest(TimestampCalculator.class) // TODO: fully document tests -> @Description for long text and reasonable // method name as short text public class RSQLUtilityTest { @Spy - private VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(new TimestampCalculator()); + private VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(); @Mock private TenantConfigurationManagement confMgmt; - @Mock - private TimestampCalculator timestampCalculator; - @Mock private Root baseSoftwareModuleRootMock; @@ -315,10 +315,10 @@ public class RSQLUtilityTest { Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); - // verfication - verify(macroResolver, times(1)).lookup(overdueProp); + // verification + verify(macroResolver).lookup(overdueProp); // the macro is unknown and hence never replaced -> #lessThanOrEqualTo is invoked with the placeholder: - verify(criteriaBuilderMock, times(1)).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), + verify(criteriaBuilderMock).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), eq(overduePropPlaceholder)); } @@ -328,12 +328,8 @@ public class RSQLUtilityTest { when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); - when(macroResolver.getTimestampCalculator()).thenReturn(new TimestampCalculator() { - @Override - protected TenantConfigurationManagement getTenantConfigurationManagement() { - return confMgmt; - } - }); + mockStatic(TimestampCalculator.class); + when(TimestampCalculator.getTenantConfigurationManagement()).thenReturn(confMgmt); return macroResolver; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index d37a2d1ee..473b2dc3a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -12,6 +12,8 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.when; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + import java.time.Instant; import org.apache.commons.lang3.text.StrSubstitutor; @@ -25,19 +27,21 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; -import org.mockito.runners.MockitoJUnitRunner; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; @Features("Unit Tests - Repository") @Stories("Placeholder resolution for virtual properties") -@RunWith(MockitoJUnitRunner.class) +@RunWith(PowerMockRunner.class) +@PrepareForTest(TimestampCalculator.class) public class VirtualPropertyResolverTest { @Spy - private VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(new TimestampCalculator()); + private VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(); @Mock private TenantConfigurationManagement confMgmt; @@ -59,12 +63,8 @@ public class VirtualPropertyResolverTest { when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); - when(resolverUnderTest.getTimestampCalculator()).thenReturn(new TimestampCalculator() { - @Override - protected TenantConfigurationManagement getTenantConfigurationManagement() { - return confMgmt; - } - }); + mockStatic(TimestampCalculator.class); + when(TimestampCalculator.getTenantConfigurationManagement()).thenReturn(confMgmt); substitutor = new StrSubstitutor(resolverUnderTest, StrSubstitutor.DEFAULT_PREFIX, diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java index 9cca4341e..ac3ed6085 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/TestConfiguration.java @@ -16,7 +16,6 @@ import org.eclipse.hawkbit.api.PropertyBasedArtifactUrlHandler; import org.eclipse.hawkbit.cache.CacheConstants; import org.eclipse.hawkbit.cache.TenancyCacheManager; import org.eclipse.hawkbit.cache.TenantAwareCacheManager; -import org.eclipse.hawkbit.repository.jpa.TimestampCalculator; import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; @@ -138,7 +137,7 @@ public class TestConfiguration implements AsyncConfigurer { */ @Bean public VirtualPropertyReplacer virtualPropertyReplacer() { - return new VirtualPropertyResolver(new TimestampCalculator()); + return new VirtualPropertyResolver(); } } diff --git a/pom.xml b/pom.xml index f83b97624..62bdfac1c 100644 --- a/pom.xml +++ b/pom.xml @@ -133,7 +133,7 @@ 2.0M10 1.4.22 2.6.2 - 1.5.4 + 1.6.5 1.0.2 19.0 1.5.2 @@ -675,6 +675,18 @@ ${pl.pragmatists.version} test + + org.powermock + powermock-module-junit4 + ${org.powermock.version} + test + + + org.powermock + powermock-api-mockito + ${org.powermock.version} + test + org.mariadb.jdbc mariadb-java-client From 39610b3730c32da997c9595747f3efc8cd45937b Mon Sep 17 00:00:00 2001 From: Dominik Herbst Date: Fri, 14 Oct 2016 10:53:17 +0200 Subject: [PATCH 17/17] Adding missing private constructor Signed-off-by: Dominik Herbst --- .../eclipse/hawkbit/repository/jpa/TimestampCalculator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java index 303c9ea3a..63813cf41 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/jpa/TimestampCalculator.java @@ -24,6 +24,9 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; */ public final class TimestampCalculator { + private TimestampCalculator() { + } + /** * Calculates the overdue timestamp (overdue_ts) based on the * current timestamp and the intervals for polling and poll-overdue: