Code format hawkbit-repository-jpa (#1928)
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
# hawkBit JPA implementation
|
# hawkBit JPA implementation
|
||||||
|
|
||||||
JPA implementation of the repository. Based on [EclipseLink](http://www.eclipse.org/eclipselink/) and [Spring Data Jpa](http://projects.spring.io/spring-data-jpa/).
|
JPA implementation of the repository. Based on [EclipseLink](http://www.eclipse.org/eclipselink/)
|
||||||
|
and [Spring Data Jpa](http://projects.spring.io/spring-data-jpa/).
|
||||||
@@ -9,155 +9,155 @@
|
|||||||
SPDX-License-Identifier: EPL-2.0
|
SPDX-License-Identifier: EPL-2.0
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
<artifactId>hawkbit-repository</artifactId>
|
<artifactId>hawkbit-repository</artifactId>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>hawkbit-repository-jpa</artifactId>
|
<artifactId>hawkbit-repository-jpa</artifactId>
|
||||||
<name>hawkBit :: Repository :: JPA Implementation</name>
|
<name>hawkBit :: Repository :: JPA Implementation</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<apt.source.dir>${project.build.directory}/generated-sources/apt/</apt.source.dir>
|
<apt.source.dir>${project.build.directory}/generated-sources/apt/</apt.source.dir>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Hawkbit -->
|
<!-- Hawkbit -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
<artifactId>hawkbit-repository-api</artifactId>
|
<artifactId>hawkbit-repository-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
<artifactId>hawkbit-repository-core</artifactId>
|
<artifactId>hawkbit-repository-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
<artifactId>hawkbit-artifact-repository-filesystem</artifactId>
|
<artifactId>hawkbit-artifact-repository-filesystem</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-core</artifactId>
|
<artifactId>spring-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.persistence</groupId>
|
<groupId>org.eclipse.persistence</groupId>
|
||||||
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-core</artifactId>
|
<artifactId>spring-security-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-mysql</artifactId>
|
<artifactId>flyway-mysql</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cz.jirutka.rsql</groupId>
|
<groupId>cz.jirutka.rsql</groupId>
|
||||||
<artifactId>rsql-parser</artifactId>
|
<artifactId>rsql-parser</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.xml.bind</groupId>
|
<groupId>javax.xml.bind</groupId>
|
||||||
<artifactId>jaxb-api</artifactId>
|
<artifactId>jaxb-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.validator</groupId>
|
<groupId>org.hibernate.validator</groupId>
|
||||||
<artifactId>hibernate-validator</artifactId>
|
<artifactId>hibernate-validator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-collections4</artifactId>
|
<artifactId>commons-collections4</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
<artifactId>hawkbit-repository-test</artifactId>
|
<artifactId>hawkbit-repository-test</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.el</groupId>
|
<groupId>javax.el</groupId>
|
||||||
<artifactId>javax.el-api</artifactId>
|
<artifactId>javax.el-api</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.qameta.allure</groupId>
|
<groupId>io.qameta.allure</groupId>
|
||||||
<artifactId>allure-junit5</artifactId>
|
<artifactId>allure-junit5</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<!-- Static weaver for EclipseLink -->
|
<!-- Static weaver for EclipseLink -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.ethlo.persistence.tools</groupId>
|
<groupId>com.ethlo.persistence.tools</groupId>
|
||||||
<artifactId>eclipselink-maven-plugin</artifactId>
|
<artifactId>eclipselink-maven-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>modelgen</id>
|
<id>modelgen</id>
|
||||||
<phase>generate-sources</phase>
|
<phase>generate-sources</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>modelgen</goal>
|
<goal>modelgen</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>process-classes</phase>
|
<phase>process-classes</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>weave</goal>
|
<goal>weave</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<basePackage>org.eclipse.hawkbit.repository.jpa.model</basePackage>
|
<basePackage>org.eclipse.hawkbit.repository.jpa.model</basePackage>
|
||||||
</configuration>
|
</configuration>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.persistence</groupId>
|
<groupId>org.eclipse.persistence</groupId>
|
||||||
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
||||||
<version>${eclipselink.version}</version>
|
<version>${eclipselink.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<!-- Should be placed here below 'eclipselink-maven-plugin' as the plugin should be executed -->
|
<!-- Should be placed here below 'eclipselink-maven-plugin' as the plugin should be executed -->
|
||||||
<!-- after the code generation and the order of the plugins in the pom is relevant for maven -->
|
<!-- after the code generation and the order of the plugins in the pom is relevant for maven -->
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>build-helper-maven-plugin</artifactId>
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>add-source</id>
|
<id>add-source</id>
|
||||||
<phase>generate-sources</phase>
|
<phase>generate-sources</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>add-source</goal>
|
<goal>add-source</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<sources>
|
<sources>
|
||||||
<source>${apt.source.dir}</source>
|
<source>${apt.source.dir}</source>
|
||||||
</sources>
|
</sources>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -19,13 +19,12 @@ import org.springframework.stereotype.Service;
|
|||||||
* used by spring caching framework to resolve the key-generator. The
|
* used by spring caching framework to resolve the key-generator. The
|
||||||
* key-generator must registered as bean so spring can resolve the key-generator
|
* key-generator must registered as bean so spring can resolve the key-generator
|
||||||
* by its name.
|
* by its name.
|
||||||
*
|
*
|
||||||
* When using the {@link Service} annotation e.g. by {@link JpaSystemManagement}
|
* When using the {@link Service} annotation e.g. by {@link JpaSystemManagement}
|
||||||
* the bean registration must be declared by the interface due spring registers
|
* the bean registration must be declared by the interface due spring registers
|
||||||
* the bean by the implemented interfaces. So introduce a single interface for
|
* the bean by the implemented interfaces. So introduce a single interface for
|
||||||
* the {@link JpaSystemManagement} implementation to allow it to register the
|
* the {@link JpaSystemManagement} implementation to allow it to register the
|
||||||
* key-generator bean.
|
* key-generator bean.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface CurrentTenantCacheKeyGenerator {
|
public interface CurrentTenantCacheKeyGenerator {
|
||||||
@@ -33,7 +32,7 @@ public interface CurrentTenantCacheKeyGenerator {
|
|||||||
/**
|
/**
|
||||||
* Bean declaration to register a {@code currentTenantKeyGenerator} bean
|
* Bean declaration to register a {@code currentTenantKeyGenerator} bean
|
||||||
* which is used by the caching framework.
|
* which is used by the caching framework.
|
||||||
*
|
*
|
||||||
* @return the {@link KeyGenerator} to be used to cache the values of the
|
* @return the {@link KeyGenerator} to be used to cache the values of the
|
||||||
* current used tenant in the {@link JpaSystemManagement}
|
* current used tenant in the {@link JpaSystemManagement}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
|
|||||||
* A {@link JpaRepositoryFactoryBean} extension that allow injection of custom
|
* A {@link JpaRepositoryFactoryBean} extension that allow injection of custom
|
||||||
* repository factories by using a {@link BaseRepositoryTypeProvider}
|
* repository factories by using a {@link BaseRepositoryTypeProvider}
|
||||||
* implementation, allows injecting different base repository implementations based on repository type
|
* implementation, allows injecting different base repository implementations based on repository type
|
||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* @param <S>
|
* @param <S>
|
||||||
* @param <ID>
|
* @param <ID>
|
||||||
@@ -36,8 +36,7 @@ public class CustomBaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
|
|||||||
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository
|
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository
|
||||||
* interface.
|
* interface.
|
||||||
*
|
*
|
||||||
* @param repositoryInterface
|
* @param repositoryInterface must not be {@literal null}.
|
||||||
* must not be {@literal null}.
|
|
||||||
*/
|
*/
|
||||||
public CustomBaseRepositoryFactoryBean(final Class<? extends T> repositoryInterface) {
|
public CustomBaseRepositoryFactoryBean(final Class<? extends T> repositoryInterface) {
|
||||||
super(repositoryInterface);
|
super(repositoryInterface);
|
||||||
|
|||||||
@@ -57,6 +57,30 @@ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy {
|
|||||||
return isApprovalEnabled() && hasNoApproveRolloutPermission(getActorAuthorities(rollout));
|
return isApprovalEnabled() && hasNoApproveRolloutPermission(getActorAuthorities(rollout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Per default do nothing.
|
||||||
|
*
|
||||||
|
* @param rollout
|
||||||
|
* rollout to create approval task for.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onApprovalRequired(final Rollout rollout) {
|
||||||
|
// do nothing per default, can be extended by further implementations.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApprovalUser(final Rollout rollout) {
|
||||||
|
return getCurrentAuthentication().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Authentication getCurrentAuthentication() {
|
||||||
|
return SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasNoApproveRolloutPermission(final Collection<String> authorities) {
|
||||||
|
return authorities.stream().noneMatch(SpPermission.APPROVE_ROLLOUT::equals);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isApprovalEnabled() {
|
private boolean isApprovalEnabled() {
|
||||||
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
|
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
|
||||||
.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue());
|
.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue());
|
||||||
@@ -78,28 +102,4 @@ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy {
|
|||||||
return ((User) getCurrentAuthentication().getPrincipal()).getAuthorities().stream()
|
return ((User) getCurrentAuthentication().getPrincipal()).getAuthorities().stream()
|
||||||
.map(GrantedAuthority::getAuthority).toList();
|
.map(GrantedAuthority::getAuthority).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Authentication getCurrentAuthentication() {
|
|
||||||
return SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasNoApproveRolloutPermission(final Collection<String> authorities) {
|
|
||||||
return authorities.stream().noneMatch(SpPermission.APPROVE_ROLLOUT::equals);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Per default do nothing.
|
|
||||||
*
|
|
||||||
* @param rollout
|
|
||||||
* rollout to create approval task for.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onApprovalRequired(final Rollout rollout) {
|
|
||||||
// do nothing per default, can be extended by further implementations.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getApprovalUser(final Rollout rollout) {
|
|
||||||
return getCurrentAuthentication().getName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,63 +27,56 @@ public interface EntityInterceptor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the {@link PrePersist} lifecycle event.
|
* Callback for the {@link PrePersist} lifecycle event.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the model entity
|
||||||
* the model entity
|
|
||||||
*/
|
*/
|
||||||
default void prePersist(final Object entity) {
|
default void prePersist(final Object entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the {@link PostPersist} lifecycle event.
|
* Callback for the {@link PostPersist} lifecycle event.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the model entity
|
||||||
* the model entity
|
|
||||||
*/
|
*/
|
||||||
default void postPersist(final Object entity) {
|
default void postPersist(final Object entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the {@link PostRemove} lifecycle event.
|
* Callback for the {@link PostRemove} lifecycle event.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the model entity
|
||||||
* the model entity
|
|
||||||
*/
|
*/
|
||||||
default void postRemove(final Object entity) {
|
default void postRemove(final Object entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the {@link PreRemove} lifecycle event.
|
* Callback for the {@link PreRemove} lifecycle event.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the model entity
|
||||||
* the model entity
|
|
||||||
*/
|
*/
|
||||||
default void preRemove(final Object entity) {
|
default void preRemove(final Object entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the {@link PostLoad} lifecycle event.
|
* Callback for the {@link PostLoad} lifecycle event.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the model entity
|
||||||
* the model entity
|
|
||||||
*/
|
*/
|
||||||
default void postLoad(final Object entity) {
|
default void postLoad(final Object entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the {@link PreUpdate} lifecycle event.
|
* Callback for the {@link PreUpdate} lifecycle event.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the model entity
|
||||||
* the model entity
|
|
||||||
*/
|
*/
|
||||||
default void preUpdate(final Object entity) {
|
default void preUpdate(final Object entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the {@link PostUpdate} lifecycle event.
|
* Callback for the {@link PostUpdate} lifecycle event.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the model entity
|
||||||
* the model entity
|
|
||||||
*/
|
*/
|
||||||
default void postUpdate(final Object entity) {
|
default void postUpdate(final Object entity) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
|
|||||||
/**
|
/**
|
||||||
* {@link EclipseLinkJpaDialect} with additional exception translation
|
* {@link EclipseLinkJpaDialect} with additional exception translation
|
||||||
* mechanisms based on {@link SQLStateSQLExceptionTranslator}.
|
* mechanisms based on {@link SQLStateSQLExceptionTranslator}.
|
||||||
*
|
*
|
||||||
* There are multiple variations of exceptions coming out of persistence
|
* There are multiple variations of exceptions coming out of persistence
|
||||||
* provider:
|
* provider:
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 1) {@link PersistenceException}s that can be mapped by
|
* 1) {@link PersistenceException}s that can be mapped by
|
||||||
* {@link EclipseLinkJpaDialect} into corresponding {@link DataAccessException}.
|
* {@link EclipseLinkJpaDialect} into corresponding {@link DataAccessException}.
|
||||||
@@ -47,9 +47,9 @@ import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
|
|||||||
* <p>
|
* <p>
|
||||||
* 3.b.) the cause is not an {@link SQLException} and as a result cannot be
|
* 3.b.) the cause is not an {@link SQLException} and as a result cannot be
|
||||||
* mapped.
|
* mapped.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class HawkBitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
|
public class HawkBitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final SQLStateSQLExceptionTranslator SQLSTATE_EXCEPTION_TRANSLATOR = new SQLStateSQLExceptionTranslator();
|
private static final SQLStateSQLExceptionTranslator SQLSTATE_EXCEPTION_TRANSLATOR = new SQLStateSQLExceptionTranslator();
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusBuilder;
|
|||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeBuilder;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagBuilder;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetBuilder;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
|
||||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||||
@@ -36,7 +35,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA Implementation of {@link EntityFactory}.
|
* JPA Implementation of {@link EntityFactory}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Validated
|
@Validated
|
||||||
public class JpaEntityFactory implements EntityFactory {
|
public class JpaEntityFactory implements EntityFactory {
|
||||||
@@ -65,6 +63,16 @@ public class JpaEntityFactory implements EntityFactory {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TargetTypeBuilder targetTypeBuilder;
|
private TargetTypeBuilder targetTypeBuilder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionStatusBuilder actionStatus() {
|
||||||
|
return new JpaActionStatusBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DistributionSetBuilder distributionSet() {
|
||||||
|
return distributionSetBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MetaData generateDsMetadata(final String key, final String value) {
|
public MetaData generateDsMetadata(final String key, final String value) {
|
||||||
return new JpaDistributionSetMetadata(key, StringUtils.trimWhitespace(value));
|
return new JpaDistributionSetMetadata(key, StringUtils.trimWhitespace(value));
|
||||||
@@ -76,23 +84,8 @@ public class JpaEntityFactory implements EntityFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DistributionSetTypeBuilder distributionSetType() {
|
public SoftwareModuleMetadataBuilder softwareModuleMetadata() {
|
||||||
return distributionSetTypeBuilder;
|
return softwareModuleMetadataBuilder;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DistributionSetBuilder distributionSet() {
|
|
||||||
return distributionSetBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetBuilder target() {
|
|
||||||
return targetBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetTypeBuilder targetType() {
|
|
||||||
return targetTypeBuilder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,8 +94,18 @@ public class JpaEntityFactory implements EntityFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetFilterQueryBuilder targetFilterQuery() {
|
public RolloutGroupBuilder rolloutGroup() {
|
||||||
return targetFilterQueryBuilder;
|
return new JpaRolloutGroupBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DistributionSetTypeBuilder distributionSetType() {
|
||||||
|
return distributionSetTypeBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RolloutBuilder rollout() {
|
||||||
|
return rolloutBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -116,23 +119,18 @@ public class JpaEntityFactory implements EntityFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionStatusBuilder actionStatus() {
|
public TargetBuilder target() {
|
||||||
return new JpaActionStatusBuilder();
|
return targetBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RolloutBuilder rollout() {
|
public TargetTypeBuilder targetType() {
|
||||||
return rolloutBuilder;
|
return targetTypeBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RolloutGroupBuilder rolloutGroup() {
|
public TargetFilterQueryBuilder targetFilterQuery() {
|
||||||
return new JpaRolloutGroupBuilder();
|
return targetFilterQueryBuilder;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SoftwareModuleMetadataBuilder softwareModuleMetadata() {
|
|
||||||
return softwareModuleMetadataBuilder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.BaseEntityRepository;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.NoCountSliceRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.NoCountSliceRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -36,6 +33,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* A collection of static helper methods for the management classes
|
* A collection of static helper methods for the management classes
|
||||||
*/
|
*/
|
||||||
public final class JpaManagementHelper {
|
public final class JpaManagementHelper {
|
||||||
|
|
||||||
private JpaManagementHelper() {
|
private JpaManagementHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa;
|
package org.eclipse.hawkbit.repository.jpa;
|
||||||
|
|
||||||
|
import static org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate.addSuccessAndErrorConditionsAndActions;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -73,8 +75,6 @@ import org.springframework.data.domain.Sort.Direction;
|
|||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.TransactionException;
|
import org.springframework.transaction.TransactionException;
|
||||||
|
|
||||||
import static org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate.addSuccessAndErrorConditionsAndActions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Jpa implementation of {@link RolloutExecutor}
|
* A Jpa implementation of {@link RolloutExecutor}
|
||||||
*/
|
*/
|
||||||
@@ -101,28 +101,25 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
*/
|
*/
|
||||||
private static final List<Status> DOWNLOAD_ONLY_ACTION_TERMINATION_STATUSES = Arrays.asList(Status.ERROR,
|
private static final List<Status> DOWNLOAD_ONLY_ACTION_TERMINATION_STATUSES = Arrays.asList(Status.ERROR,
|
||||||
Status.FINISHED, Status.CANCELED, Status.DOWNLOADED);
|
Status.FINISHED, Status.CANCELED, Status.DOWNLOADED);
|
||||||
|
private static final Comparator<RolloutGroup> DESC_COMP = Comparator.comparingLong(RolloutGroup::getId).reversed();
|
||||||
private final ActionRepository actionRepository;
|
private final ActionRepository actionRepository;
|
||||||
private final RolloutGroupRepository rolloutGroupRepository;
|
private final RolloutGroupRepository rolloutGroupRepository;
|
||||||
private final RolloutTargetGroupRepository rolloutTargetGroupRepository;
|
private final RolloutTargetGroupRepository rolloutTargetGroupRepository;
|
||||||
private final RolloutRepository rolloutRepository;
|
private final RolloutRepository rolloutRepository;
|
||||||
|
|
||||||
private final TargetManagement targetManagement;
|
private final TargetManagement targetManagement;
|
||||||
private final DeploymentManagement deploymentManagement;
|
private final DeploymentManagement deploymentManagement;
|
||||||
private final RolloutGroupManagement rolloutGroupManagement;
|
private final RolloutGroupManagement rolloutGroupManagement;
|
||||||
private final RolloutManagement rolloutManagement;
|
private final RolloutManagement rolloutManagement;
|
||||||
private final QuotaManagement quotaManagement;
|
private final QuotaManagement quotaManagement;
|
||||||
|
|
||||||
private final RolloutGroupEvaluationManager evaluationManager;
|
private final RolloutGroupEvaluationManager evaluationManager;
|
||||||
private final RolloutApprovalStrategy rolloutApprovalStrategy;
|
private final RolloutApprovalStrategy rolloutApprovalStrategy;
|
||||||
|
|
||||||
private final EntityManager entityManager;
|
private final EntityManager entityManager;
|
||||||
private final PlatformTransactionManager txManager;
|
private final PlatformTransactionManager txManager;
|
||||||
private final AfterTransactionCommitExecutor afterCommit;
|
private final AfterTransactionCommitExecutor afterCommit;
|
||||||
private final EventPublisherHolder eventPublisherHolder;
|
private final EventPublisherHolder eventPublisherHolder;
|
||||||
|
|
||||||
private final TenantAware tenantAware;
|
private final TenantAware tenantAware;
|
||||||
private final RepositoryProperties repositoryProperties;
|
private final RepositoryProperties repositoryProperties;
|
||||||
|
private final Map<Long, AtomicLong> lastDynamicGroupFill = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public JpaRolloutExecutor(
|
public JpaRolloutExecutor(
|
||||||
final ActionRepository actionRepository, final RolloutGroupRepository rolloutGroupRepository,
|
final ActionRepository actionRepository, final RolloutGroupRepository rolloutGroupRepository,
|
||||||
@@ -158,48 +155,48 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
log.debug("Processing rollout {}", rollout.getId());
|
log.debug("Processing rollout {}", rollout.getId());
|
||||||
|
|
||||||
switch (rollout.getStatus()) {
|
switch (rollout.getStatus()) {
|
||||||
case CREATING:
|
case CREATING:
|
||||||
handleCreateRollout((JpaRollout) rollout);
|
handleCreateRollout((JpaRollout) rollout);
|
||||||
break;
|
break;
|
||||||
case READY:
|
case READY:
|
||||||
handleReadyRollout(rollout);
|
handleReadyRollout(rollout);
|
||||||
break;
|
break;
|
||||||
case STARTING:
|
case STARTING:
|
||||||
// the lastModifiedBy user is probably the user that has actually called the rollout start (unless overridden) - not the creator
|
// the lastModifiedBy user is probably the user that has actually called the rollout start (unless overridden) - not the creator
|
||||||
SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy());
|
SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy());
|
||||||
try {
|
try {
|
||||||
handleStartingRollout(rollout);
|
handleStartingRollout(rollout);
|
||||||
} finally {
|
} finally {
|
||||||
// clear, ALWAYS, the set auditor override
|
// clear, ALWAYS, the set auditor override
|
||||||
SpringSecurityAuditorAware.clearAuditorOverride();
|
SpringSecurityAuditorAware.clearAuditorOverride();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RUNNING:
|
case RUNNING:
|
||||||
handleRunningRollout((JpaRollout) rollout);
|
handleRunningRollout((JpaRollout) rollout);
|
||||||
break;
|
break;
|
||||||
case STOPPING:
|
case STOPPING:
|
||||||
// the lastModifiedBy user is probably the user that has actually called the rollout stop (unless overridden) - not the creator
|
// the lastModifiedBy user is probably the user that has actually called the rollout stop (unless overridden) - not the creator
|
||||||
SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy());
|
SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy());
|
||||||
try {
|
try {
|
||||||
handleStopRollout((JpaRollout) rollout);
|
handleStopRollout((JpaRollout) rollout);
|
||||||
} finally {
|
} finally {
|
||||||
// clear, ALWAYS, the set auditor override
|
// clear, ALWAYS, the set auditor override
|
||||||
SpringSecurityAuditorAware.clearAuditorOverride();
|
SpringSecurityAuditorAware.clearAuditorOverride();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DELETING:
|
case DELETING:
|
||||||
// the lastModifiedBy user is probably the user that has actually called the rollout delete (unless overridden) - not the creator
|
// the lastModifiedBy user is probably the user that has actually called the rollout delete (unless overridden) - not the creator
|
||||||
SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy());
|
SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy());
|
||||||
try {
|
try {
|
||||||
handleDeleteRollout((JpaRollout) rollout);
|
handleDeleteRollout((JpaRollout) rollout);
|
||||||
} finally {
|
} finally {
|
||||||
// clear, ALWAYS, the set auditor override
|
// clear, ALWAYS, the set auditor override
|
||||||
SpringSecurityAuditorAware.clearAuditorOverride();
|
SpringSecurityAuditorAware.clearAuditorOverride();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.error("Rollout in status {} not supposed to be handled!", rollout.getStatus());
|
log.error("Rollout in status {} not supposed to be handled!", rollout.getStatus());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Rollout {} processed", rollout.getId());
|
log.debug("Rollout {} processed", rollout.getId());
|
||||||
@@ -312,9 +309,9 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
|
|
||||||
rolloutGroupRepository.findByRolloutAndStatusNotIn(rollout,
|
rolloutGroupRepository.findByRolloutAndStatusNotIn(rollout,
|
||||||
Arrays.asList(RolloutGroupStatus.FINISHED, RolloutGroupStatus.ERROR)).forEach(rolloutGroup -> {
|
Arrays.asList(RolloutGroupStatus.FINISHED, RolloutGroupStatus.ERROR)).forEach(rolloutGroup -> {
|
||||||
rolloutGroup.setStatus(RolloutGroupStatus.FINISHED);
|
rolloutGroup.setStatus(RolloutGroupStatus.FINISHED);
|
||||||
rolloutGroupRepository.save(rolloutGroup);
|
rolloutGroupRepository.save(rolloutGroup);
|
||||||
});
|
});
|
||||||
|
|
||||||
rollout.setStatus(RolloutStatus.FINISHED);
|
rollout.setStatus(RolloutStatus.FINISHED);
|
||||||
rolloutRepository.save(rollout);
|
rolloutRepository.save(rollout);
|
||||||
@@ -417,7 +414,6 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
return groupsActiveLeft == 0;
|
return groupsActiveLeft == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Comparator<RolloutGroup> DESC_COMP = Comparator.comparingLong(RolloutGroup::getId).reversed();
|
|
||||||
private void executeLatestRolloutGroup(final JpaRollout rollout) {
|
private void executeLatestRolloutGroup(final JpaRollout rollout) {
|
||||||
// was - rolloutGroupRepository.findByRolloutAndStatusNotOrderByIdDesc(rollout, RolloutGroupStatus.SCHEDULED);
|
// was - rolloutGroupRepository.findByRolloutAndStatusNotOrderByIdDesc(rollout, RolloutGroupStatus.SCHEDULED);
|
||||||
final List<JpaRolloutGroup> latestRolloutGroup = rollout.getRolloutGroups().stream()
|
final List<JpaRolloutGroup> latestRolloutGroup = rollout.getRolloutGroups().stream()
|
||||||
@@ -435,10 +431,10 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
// so the evaluation to use total targets to properly
|
// so the evaluation to use total targets to properly
|
||||||
private RolloutGroup evalProxy(final RolloutGroup group) {
|
private RolloutGroup evalProxy(final RolloutGroup group) {
|
||||||
if (group.isDynamic()) {
|
if (group.isDynamic()) {
|
||||||
final int expected = Math.max((int)group.getTargetPercentage(), 1);
|
final int expected = Math.max((int) group.getTargetPercentage(), 1);
|
||||||
return (RolloutGroup) Proxy.newProxyInstance(
|
return (RolloutGroup) Proxy.newProxyInstance(
|
||||||
RolloutGroup.class.getClassLoader(),
|
RolloutGroup.class.getClassLoader(),
|
||||||
new Class<?>[] {RolloutGroup.class},
|
new Class<?>[] { RolloutGroup.class },
|
||||||
(proxy, method, args) -> {
|
(proxy, method, args) -> {
|
||||||
if ("getTotalTargets".equals(method.getName())) {
|
if ("getTotalTargets".equals(method.getName())) {
|
||||||
return expected;
|
return expected;
|
||||||
@@ -601,14 +597,14 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
long targetsInGroupFilter;
|
long targetsInGroupFilter;
|
||||||
if (!RolloutHelper.isRolloutRetried(rollout.getTargetFilterQuery())) {
|
if (!RolloutHelper.isRolloutRetried(rollout.getTargetFilterQuery())) {
|
||||||
targetsInGroupFilter = DeploymentHelper.runInNewTransaction(txManager,
|
targetsInGroupFilter = DeploymentHelper.runInNewTransaction(txManager,
|
||||||
"countAllTargetsByTargetFilterQueryAndNotInRolloutGroups",
|
"countAllTargetsByTargetFilterQueryAndNotInRolloutGroups",
|
||||||
count -> targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(readyGroups,
|
count -> targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(readyGroups,
|
||||||
groupTargetFilter, rollout.getDistributionSet().getType()));
|
groupTargetFilter, rollout.getDistributionSet().getType()));
|
||||||
} else {
|
} else {
|
||||||
targetsInGroupFilter = DeploymentHelper.runInNewTransaction(txManager,
|
targetsInGroupFilter = DeploymentHelper.runInNewTransaction(txManager,
|
||||||
"countByFailedRolloutAndNotInRolloutGroupsAndCompatible",
|
"countByFailedRolloutAndNotInRolloutGroupsAndCompatible",
|
||||||
count -> targetManagement.countByFailedRolloutAndNotInRolloutGroups(readyGroups,
|
count -> targetManagement.countByFailedRolloutAndNotInRolloutGroups(readyGroups,
|
||||||
RolloutHelper.getIdFromRetriedTargetFilter(rollout.getTargetFilterQuery())));
|
RolloutHelper.getIdFromRetriedTargetFilter(rollout.getTargetFilterQuery())));
|
||||||
}
|
}
|
||||||
|
|
||||||
final double percentFromTheRest;
|
final double percentFromTheRest;
|
||||||
@@ -677,7 +673,6 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<Long, AtomicLong> lastDynamicGroupFill = new ConcurrentHashMap<>();
|
|
||||||
// return if group change is made
|
// return if group change is made
|
||||||
private boolean fillDynamicRolloutGroupsWithTargets(final JpaRollout rollout) {
|
private boolean fillDynamicRolloutGroupsWithTargets(final JpaRollout rollout) {
|
||||||
final AtomicLong lastFill = lastDynamicGroupFill.computeIfAbsent(rollout.getId(), id -> new AtomicLong(0));
|
final AtomicLong lastFill = lastDynamicGroupFill.computeIfAbsent(rollout.getId(), id -> new AtomicLong(0));
|
||||||
@@ -690,9 +685,9 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
RolloutHelper.verifyRolloutInStatus(rollout, RolloutStatus.RUNNING);
|
RolloutHelper.verifyRolloutInStatus(rollout, RolloutStatus.RUNNING);
|
||||||
final List<RolloutGroup> rolloutGroups = rollout.getRolloutGroups();
|
final List<RolloutGroup> rolloutGroups = rollout.getRolloutGroups();
|
||||||
|
|
||||||
final JpaRolloutGroup group = (JpaRolloutGroup)rolloutGroups.get(rolloutGroups.size() - 1);
|
final JpaRolloutGroup group = (JpaRolloutGroup) rolloutGroups.get(rolloutGroups.size() - 1);
|
||||||
|
|
||||||
final long expectedInGroup = Math.max((int)group.getTargetPercentage(), 1);
|
final long expectedInGroup = Math.max((int) group.getTargetPercentage(), 1);
|
||||||
final long currentlyInGroup = group.getTotalTargets();
|
final long currentlyInGroup = group.getTotalTargets();
|
||||||
if (currentlyInGroup >= expectedInGroup || group.getStatus() == RolloutGroupStatus.FINISHED) {
|
if (currentlyInGroup >= expectedInGroup || group.getStatus() == RolloutGroupStatus.FINISHED) {
|
||||||
// the last one is full. create new and start filling it on the next iteration
|
// the last one is full. create new and start filling it on the next iteration
|
||||||
@@ -741,7 +736,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createDynamicGroup(final JpaRollout rollout, final RolloutGroup lastGroup, final int groupCount, final RolloutGroupStatus status) {
|
private void createDynamicGroup(final JpaRollout rollout, final RolloutGroup lastGroup, final int groupCount,
|
||||||
|
final RolloutGroupStatus status) {
|
||||||
try {
|
try {
|
||||||
RolloutHelper.verifyRolloutGroupAmount(groupCount + 1, quotaManagement);
|
RolloutHelper.verifyRolloutGroupAmount(groupCount + 1, quotaManagement);
|
||||||
} catch (final AssignmentQuotaExceededException e) {
|
} catch (final AssignmentQuotaExceededException e) {
|
||||||
@@ -755,7 +751,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
|
|
||||||
final JpaRolloutGroup group = new JpaRolloutGroup();
|
final JpaRolloutGroup group = new JpaRolloutGroup();
|
||||||
final String lastGroupWithoutSuffix = "group-" + groupCount;
|
final String lastGroupWithoutSuffix = "group-" + groupCount;
|
||||||
final String suffix = lastGroup.getName().startsWith(lastGroupWithoutSuffix) ? lastGroup.getName().substring(lastGroupWithoutSuffix.length()) : "";
|
final String suffix = lastGroup.getName().startsWith(lastGroupWithoutSuffix) ? lastGroup.getName()
|
||||||
|
.substring(lastGroupWithoutSuffix.length()) : "";
|
||||||
final String nameAndDesc = "group-" + (groupCount + 1) + suffix;
|
final String nameAndDesc = "group-" + (groupCount + 1) + suffix;
|
||||||
group.setName(nameAndDesc);
|
group.setName(nameAndDesc);
|
||||||
group.setDescription(nameAndDesc);
|
group.setDescription(nameAndDesc);
|
||||||
|
|||||||
@@ -37,17 +37,12 @@ public class JpaRolloutHandler implements RolloutHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param tenantAware
|
* @param tenantAware the {@link TenantAware} bean holding the tenant information
|
||||||
* the {@link TenantAware} bean holding the tenant information
|
* @param rolloutManagement to fetch rollout related information from the datasource
|
||||||
* @param rolloutManagement
|
* @param rolloutExecutor to trigger executions for a specific rollout
|
||||||
* to fetch rollout related information from the datasource
|
* @param lockRegistry to lock processes
|
||||||
* @param rolloutExecutor
|
* @param txManager transaction manager interface
|
||||||
* to trigger executions for a specific rollout
|
|
||||||
* @param lockRegistry
|
|
||||||
* to lock processes
|
|
||||||
* @param txManager
|
|
||||||
* transaction manager interface
|
|
||||||
*/
|
*/
|
||||||
public JpaRolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
|
public JpaRolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
|
||||||
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
|
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
|
||||||
@@ -83,8 +78,9 @@ public class JpaRolloutHandler implements RolloutHandler {
|
|||||||
try {
|
try {
|
||||||
handleRolloutInNewTransaction(rolloutId, handlerId);
|
handleRolloutInNewTransaction(rolloutId, handlerId);
|
||||||
} catch (final Throwable throwable) {
|
} catch (final Throwable throwable) {
|
||||||
log.error("Failed to process rollout with id {}", rolloutId , throwable);
|
log.error("Failed to process rollout with id {}", rolloutId, throwable);
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
log.debug("Finished handling of the rollouts.");
|
log.debug("Finished handling of the rollouts.");
|
||||||
} finally {
|
} finally {
|
||||||
if (log.isTraceEnabled()) {
|
if (log.isTraceEnabled()) {
|
||||||
@@ -107,17 +103,17 @@ public class JpaRolloutHandler implements RolloutHandler {
|
|||||||
// auditor is retrieved and set on transaction commit
|
// auditor is retrieved and set on transaction commit
|
||||||
// if not overridden, the system user will be the auditor
|
// if not overridden, the system user will be the auditor
|
||||||
rollout.getAccessControlContext().ifPresentOrElse(
|
rollout.getAccessControlContext().ifPresentOrElse(
|
||||||
context -> // has stored context - executes it with it
|
context -> // has stored context - executes it with it
|
||||||
contextAware.runInContext(
|
contextAware.runInContext(
|
||||||
context,
|
context,
|
||||||
() -> rolloutExecutor.execute(rollout)),
|
() -> rolloutExecutor.execute(rollout)),
|
||||||
() -> // has no stored context - executes it in the tenant & user scope
|
() -> // has no stored context - executes it in the tenant & user scope
|
||||||
contextAware.runAsTenantAsUser(
|
contextAware.runAsTenantAsUser(
|
||||||
contextAware.getCurrentTenant(),
|
contextAware.getCurrentTenant(),
|
||||||
rollout.getCreatedBy(), () -> {
|
rollout.getCreatedBy(), () -> {
|
||||||
rolloutExecutor.execute(rollout);
|
rolloutExecutor.execute(rollout);
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
() -> log.error("Could not retrieve rollout with id {}. Will not continue with execution.",
|
() -> log.error("Could not retrieve rollout with id {}. Will not continue with execution.",
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.validation.Validation;
|
import jakarta.validation.Validation;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.ContextAware;
|
import org.eclipse.hawkbit.ContextAware;
|
||||||
@@ -120,11 +121,11 @@ import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetMetadataRepo
|
|||||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.repository.HawkBitBaseRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.HawkBitBaseRepository;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||||
@@ -155,9 +156,9 @@ import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
|||||||
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
|
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||||
|
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
||||||
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
|
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
|
||||||
import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory;
|
import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory;
|
||||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
|
||||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||||
@@ -202,7 +203,6 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* General configuration for hawkBit's Repository.
|
* General configuration for hawkBit's Repository.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@EnableJpaRepositories(value = "org.eclipse.hawkbit.repository.jpa.repository", repositoryFactoryBeanClass = CustomBaseRepositoryFactoryBean.class)
|
@EnableJpaRepositories(value = "org.eclipse.hawkbit.repository.jpa.repository", repositoryFactoryBeanClass = CustomBaseRepositoryFactoryBean.class)
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
@@ -223,10 +223,110 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
super(dataSource, properties, jtaTransactionManagerProvider);
|
super(dataSource, properties, jtaTransactionManagerProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the validation processor bean.
|
||||||
|
*
|
||||||
|
* @return the {@link MethodValidationPostProcessor}
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MethodValidationPostProcessor methodValidationPostProcessor() {
|
||||||
|
final MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
|
||||||
|
// ValidatorFactory shall NOT be closed because after closing the generated Validator
|
||||||
|
// methods shall not be called - we need the validator in future
|
||||||
|
processor.setValidator(Validation.byDefaultProvider().configure()
|
||||||
|
.addProperty(BaseHibernateValidatorConfiguration.ALLOW_PARALLEL_METHODS_DEFINE_PARAMETER_CONSTRAINTS,
|
||||||
|
"true")
|
||||||
|
.buildValidatorFactory().getValidator());
|
||||||
|
return processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link MultiTenantJpaTransactionManager} bean.
|
||||||
|
*
|
||||||
|
* @return a new {@link PlatformTransactionManager}
|
||||||
|
* @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#transactionManager(ObjectProvider)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager transactionManager(
|
||||||
|
final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
|
||||||
|
return new MultiTenantJpaTransactionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
|
||||||
|
return new EclipseLinkJpaVendorAdapter() {
|
||||||
|
|
||||||
|
private final HawkBitEclipseLinkJpaDialect jpaDialect = new HawkBitEclipseLinkJpaDialect();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EclipseLinkJpaDialect getJpaDialect() {
|
||||||
|
return jpaDialect;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> getVendorProperties() {
|
||||||
|
final Map<String, Object> properties = new HashMap<>(7);
|
||||||
|
// Turn off dynamic weaving to disable LTW lookup in static weaving mode
|
||||||
|
properties.put(PersistenceUnitProperties.WEAVING, "false");
|
||||||
|
// needed for reports
|
||||||
|
properties.put(PersistenceUnitProperties.ALLOW_NATIVE_SQL_QUERIES, "true");
|
||||||
|
// flyway
|
||||||
|
properties.put(PersistenceUnitProperties.DDL_GENERATION, "none");
|
||||||
|
// Embed into hawkBit logging
|
||||||
|
properties.put(PersistenceUnitProperties.LOGGING_LOGGER, "JavaLogger");
|
||||||
|
// Ensure that we flush only at the end of the transaction
|
||||||
|
properties.put(PersistenceUnitProperties.PERSISTENCE_CONTEXT_FLUSH_MODE, "COMMIT");
|
||||||
|
// Enable batch writing
|
||||||
|
properties.put(PersistenceUnitProperties.BATCH_WRITING, "JDBC");
|
||||||
|
// Batch size
|
||||||
|
properties.put(PersistenceUnitProperties.BATCH_WRITING_SIZE, "500");
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BeanPostProcessor entityManagerBeanPostProcessor(
|
||||||
|
@Autowired(required = false) final AccessController<JpaArtifact> artifactAccessController,
|
||||||
|
@Autowired(required = false) final AccessController<JpaSoftwareModuleType> softwareModuleTypeAccessController,
|
||||||
|
@Autowired(required = false) final AccessController<JpaSoftwareModule> softwareModuleAccessController,
|
||||||
|
@Autowired(required = false) final AccessController<JpaDistributionSetType> distributionSetTypeAccessController,
|
||||||
|
@Autowired(required = false) final AccessController<JpaDistributionSet> distributionSetAccessController,
|
||||||
|
@Autowired(required = false) final AccessController<JpaTargetType> targetTypeAccessControlManager,
|
||||||
|
@Autowired(required = false) final AccessController<JpaTarget> targetAccessControlManager,
|
||||||
|
@Autowired(required = false) final AccessController<JpaAction> actionAccessController) {
|
||||||
|
return new BeanPostProcessor() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName)
|
||||||
|
throws BeansException {
|
||||||
|
if (bean instanceof LocalArtifactRepository repo) {
|
||||||
|
return repo.withACM(artifactAccessController);
|
||||||
|
} else if (bean instanceof SoftwareModuleTypeRepository repo) {
|
||||||
|
return repo.withACM(softwareModuleTypeAccessController);
|
||||||
|
} else if (bean instanceof SoftwareModuleRepository repo) {
|
||||||
|
return repo.withACM(softwareModuleAccessController);
|
||||||
|
} else if (bean instanceof DistributionSetTypeRepository repo) {
|
||||||
|
return repo.withACM(distributionSetTypeAccessController);
|
||||||
|
} else if (bean instanceof DistributionSetRepository repo) {
|
||||||
|
return repo.withACM(distributionSetAccessController);
|
||||||
|
} else if (bean instanceof TargetTypeRepository repo) {
|
||||||
|
return repo.withACM(targetTypeAccessControlManager);
|
||||||
|
} else if (bean instanceof TargetRepository repo) {
|
||||||
|
return repo.withACM(targetAccessControlManager);
|
||||||
|
} else if (bean instanceof ActionRepository repo) {
|
||||||
|
return repo.withACM(actionAccessController);
|
||||||
|
}
|
||||||
|
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
PauseRolloutGroupAction pauseRolloutGroupAction(final RolloutManagement rolloutManagement,
|
PauseRolloutGroupAction pauseRolloutGroupAction(final RolloutManagement rolloutManagement,
|
||||||
final RolloutGroupRepository rolloutGroupRepository, final SystemSecurityContext systemSecurityContext) {
|
final RolloutGroupRepository rolloutGroupRepository, final SystemSecurityContext systemSecurityContext) {
|
||||||
return new PauseRolloutGroupAction(rolloutManagement, rolloutGroupRepository, systemSecurityContext);
|
return new PauseRolloutGroupAction(rolloutManagement, rolloutGroupRepository, systemSecurityContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,10 +399,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param distributionSetTypeManagement
|
* @param distributionSetTypeManagement to loading the {@link DistributionSetType}
|
||||||
* to loading the {@link DistributionSetType}
|
* @param softwareManagement for loading {@link DistributionSet#getModules()}
|
||||||
* @param softwareManagement
|
|
||||||
* for loading {@link DistributionSet#getModules()}
|
|
||||||
* @return DistributionSetBuilder bean
|
* @return DistributionSetBuilder bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -317,8 +415,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dsTypeManagement
|
* @param dsTypeManagement for loading {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||||
* for loading {@link TargetType#getCompatibleDistributionSetTypes()}
|
|
||||||
* @return TargetTypeBuilder bean
|
* @return TargetTypeBuilder bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -333,9 +430,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param softwareModuleTypeManagement
|
* @param softwareModuleTypeManagement for loading {@link DistributionSetType#getMandatoryModuleTypes()}
|
||||||
* for loading {@link DistributionSetType#getMandatoryModuleTypes()}
|
* and {@link DistributionSetType#getOptionalModuleTypes()}
|
||||||
* and {@link DistributionSetType#getOptionalModuleTypes()}
|
|
||||||
* @return DistributionSetTypeBuilder bean
|
* @return DistributionSetTypeBuilder bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -345,8 +441,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param softwareModuleTypeManagement
|
* @param softwareModuleTypeManagement for loading {@link SoftwareModule#getType()}
|
||||||
* for loading {@link SoftwareModule#getType()}
|
|
||||||
* @return SoftwareModuleBuilder bean
|
* @return SoftwareModuleBuilder bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -355,8 +450,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param distributionSetManagement
|
* @param distributionSetManagement for loading {@link Rollout#getDistributionSet()}
|
||||||
* for loading {@link Rollout#getDistributionSet()}
|
|
||||||
* @return RolloutBuilder bean
|
* @return RolloutBuilder bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -365,9 +459,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param distributionSetManagement
|
* @param distributionSetManagement for loading
|
||||||
* for loading
|
* {@link TargetFilterQuery#getAutoAssignDistributionSet()}
|
||||||
* {@link TargetFilterQuery#getAutoAssignDistributionSet()}
|
|
||||||
* @return TargetFilterQueryBuilder bean
|
* @return TargetFilterQueryBuilder bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -434,7 +527,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @return the singleton instance of the
|
* @return the singleton instance of the
|
||||||
* {@link AfterTransactionCommitExecutorHolder}
|
* {@link AfterTransactionCommitExecutorHolder}
|
||||||
*/
|
*/
|
||||||
@@ -443,23 +535,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
return AfterTransactionCommitExecutorHolder.getInstance();
|
return AfterTransactionCommitExecutorHolder.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the validation processor bean.
|
|
||||||
*
|
|
||||||
* @return the {@link MethodValidationPostProcessor}
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public MethodValidationPostProcessor methodValidationPostProcessor() {
|
|
||||||
final MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
|
|
||||||
// ValidatorFactory shall NOT be closed because after closing the generated Validator
|
|
||||||
// methods shall not be called - we need the validator in future
|
|
||||||
processor.setValidator(Validation.byDefaultProvider().configure()
|
|
||||||
.addProperty(BaseHibernateValidatorConfiguration.ALLOW_PARALLEL_METHODS_DEFINE_PARAMETER_CONSTRAINTS,
|
|
||||||
"true")
|
|
||||||
.buildValidatorFactory().getValidator());
|
|
||||||
return processor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@link ExceptionMappingAspectHandler} aspect bean
|
* @return {@link ExceptionMappingAspectHandler} aspect bean
|
||||||
*/
|
*/
|
||||||
@@ -468,51 +543,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
return new ExceptionMappingAspectHandler();
|
return new ExceptionMappingAspectHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
|
|
||||||
return new EclipseLinkJpaVendorAdapter() {
|
|
||||||
private final HawkBitEclipseLinkJpaDialect jpaDialect = new HawkBitEclipseLinkJpaDialect();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EclipseLinkJpaDialect getJpaDialect() {
|
|
||||||
return jpaDialect;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Map<String, Object> getVendorProperties() {
|
|
||||||
final Map<String, Object> properties = new HashMap<>(7);
|
|
||||||
// Turn off dynamic weaving to disable LTW lookup in static weaving mode
|
|
||||||
properties.put(PersistenceUnitProperties.WEAVING, "false");
|
|
||||||
// needed for reports
|
|
||||||
properties.put(PersistenceUnitProperties.ALLOW_NATIVE_SQL_QUERIES, "true");
|
|
||||||
// flyway
|
|
||||||
properties.put(PersistenceUnitProperties.DDL_GENERATION, "none");
|
|
||||||
// Embed into hawkBit logging
|
|
||||||
properties.put(PersistenceUnitProperties.LOGGING_LOGGER, "JavaLogger");
|
|
||||||
// Ensure that we flush only at the end of the transaction
|
|
||||||
properties.put(PersistenceUnitProperties.PERSISTENCE_CONTEXT_FLUSH_MODE, "COMMIT");
|
|
||||||
// Enable batch writing
|
|
||||||
properties.put(PersistenceUnitProperties.BATCH_WRITING, "JDBC");
|
|
||||||
// Batch size
|
|
||||||
properties.put(PersistenceUnitProperties.BATCH_WRITING_SIZE, "500");
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link MultiTenantJpaTransactionManager} bean.
|
|
||||||
*
|
|
||||||
* @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#transactionManager(ObjectProvider)
|
|
||||||
* @return a new {@link PlatformTransactionManager}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Bean
|
|
||||||
public PlatformTransactionManager transactionManager(
|
|
||||||
final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
|
|
||||||
return new MultiTenantJpaTransactionManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link JpaSystemManagement} bean.
|
* {@link JpaSystemManagement} bean.
|
||||||
*
|
*
|
||||||
@@ -614,13 +644,13 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
TargetManagement targetManagement(final EntityManager entityManager, final QuotaManagement quotaManagement,
|
TargetManagement targetManagement(final EntityManager entityManager, final QuotaManagement quotaManagement,
|
||||||
final TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
final TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||||
final RolloutGroupRepository rolloutGroupRepository,
|
final RolloutGroupRepository rolloutGroupRepository,
|
||||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||||
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
|
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
|
||||||
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||||
final JpaProperties properties, final DistributionSetManagement distributionSetManagement) {
|
final JpaProperties properties, final DistributionSetManagement distributionSetManagement) {
|
||||||
return new JpaTargetManagement(entityManager, distributionSetManagement, quotaManagement, targetRepository,
|
return new JpaTargetManagement(entityManager, distributionSetManagement, quotaManagement, targetRepository,
|
||||||
targetTypeRepository, targetMetadataRepository, rolloutGroupRepository, targetFilterQueryRepository,
|
targetTypeRepository, targetMetadataRepository, rolloutGroupRepository, targetFilterQueryRepository,
|
||||||
targetTagRepository, eventPublisherHolder, tenantAware, virtualPropertyReplacer,
|
targetTagRepository, eventPublisherHolder, tenantAware, virtualPropertyReplacer,
|
||||||
@@ -630,19 +660,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
/**
|
/**
|
||||||
* {@link JpaTargetFilterQueryManagement} bean.
|
* {@link JpaTargetFilterQueryManagement} bean.
|
||||||
*
|
*
|
||||||
* @param targetFilterQueryRepository
|
* @param targetFilterQueryRepository holding {@link TargetFilterQuery} entities
|
||||||
* holding {@link TargetFilterQuery} entities
|
* @param targetManagement managing {@link Target} entities
|
||||||
* @param targetManagement
|
* @param virtualPropertyReplacer for RSQL handling
|
||||||
* managing {@link Target} entities
|
* @param distributionSetManagement for auto assign DS access
|
||||||
* @param virtualPropertyReplacer
|
* @param quotaManagement to access quotas
|
||||||
* for RSQL handling
|
* @param properties JPA properties
|
||||||
* @param distributionSetManagement
|
|
||||||
* for auto assign DS access
|
|
||||||
* @param quotaManagement
|
|
||||||
* to access quotas
|
|
||||||
* @param properties
|
|
||||||
* JPA properties
|
|
||||||
*
|
|
||||||
* @return a new {@link TargetFilterQueryManagement}
|
* @return a new {@link TargetFilterQueryManagement}
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -659,7 +682,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
tenantConfigurationManagement, repositoryProperties, systemSecurityContext, contextAware, auditorAware);
|
tenantConfigurationManagement, repositoryProperties, systemSecurityContext, contextAware, auditorAware);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link JpaTargetTagManagement} bean.
|
* {@link JpaTargetTagManagement} bean.
|
||||||
*
|
*
|
||||||
@@ -792,10 +814,10 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
RolloutGroupManagement rolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
RolloutGroupManagement rolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||||
final TargetRepository targetRepository, final EntityManager entityManager,
|
final TargetRepository targetRepository, final EntityManager entityManager,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
||||||
final JpaProperties properties) {
|
final JpaProperties properties) {
|
||||||
return new JpaRolloutGroupManagement(rolloutGroupRepository, rolloutRepository, actionRepository,
|
return new JpaRolloutGroupManagement(rolloutGroupRepository, rolloutRepository, actionRepository,
|
||||||
targetRepository, entityManager, virtualPropertyReplacer, rolloutStatusCache, properties.getDatabase());
|
targetRepository, entityManager, virtualPropertyReplacer, rolloutStatusCache, properties.getDatabase());
|
||||||
}
|
}
|
||||||
@@ -808,15 +830,16 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
DeploymentManagement deploymentManagement(final EntityManager entityManager,
|
DeploymentManagement deploymentManagement(final EntityManager entityManager,
|
||||||
final ActionRepository actionRepository,
|
final ActionRepository actionRepository,
|
||||||
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
|
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
|
||||||
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
|
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
|
||||||
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement, targetRepository, actionStatusRepository, auditorProvider,
|
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement, targetRepository, actionStatusRepository,
|
||||||
|
auditorProvider,
|
||||||
eventPublisherHolder, afterCommit, virtualPropertyReplacer, txManager, tenantConfigurationManagement,
|
eventPublisherHolder, afterCommit, virtualPropertyReplacer, txManager, tenantConfigurationManagement,
|
||||||
quotaManagement, systemSecurityContext, tenantAware, auditorAware, properties.getDatabase(), repositoryProperties);
|
quotaManagement, systemSecurityContext, tenantAware, auditorAware, properties.getDatabase(), repositoryProperties);
|
||||||
}
|
}
|
||||||
@@ -880,10 +903,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
/**
|
/**
|
||||||
* {@link EventEntityManager} bean.
|
* {@link EventEntityManager} bean.
|
||||||
*
|
*
|
||||||
* @param aware
|
* @param aware the tenant aware
|
||||||
* the tenant aware
|
* @param entityManager the entity manager
|
||||||
* @param entityManager
|
|
||||||
* the entity manager
|
|
||||||
* @return a new {@link EventEntityManager}
|
* @return a new {@link EventEntityManager}
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -895,14 +916,10 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
/**
|
/**
|
||||||
* {@link AutoAssignChecker} bean.
|
* {@link AutoAssignChecker} bean.
|
||||||
*
|
*
|
||||||
* @param targetFilterQueryManagement
|
* @param targetFilterQueryManagement to get all target filter queries
|
||||||
* to get all target filter queries
|
* @param targetManagement to get targets
|
||||||
* @param targetManagement
|
* @param deploymentManagement to assign distribution sets to targets
|
||||||
* to get targets
|
* @param transactionManager to run transactions
|
||||||
* @param deploymentManagement
|
|
||||||
* to assign distribution sets to targets
|
|
||||||
* @param transactionManager
|
|
||||||
* to run transactions
|
|
||||||
* @return a new {@link AutoAssignChecker}
|
* @return a new {@link AutoAssignChecker}
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -920,14 +937,10 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
* Note: does not activate in test profile, otherwise it is hard to test the
|
* Note: does not activate in test profile, otherwise it is hard to test the
|
||||||
* auto assign functionality.
|
* auto assign functionality.
|
||||||
*
|
*
|
||||||
* @param systemManagement
|
* @param systemManagement to find all tenants
|
||||||
* to find all tenants
|
* @param systemSecurityContext to run as system
|
||||||
* @param systemSecurityContext
|
* @param autoAssignExecutor to run a check as tenant
|
||||||
* to run as system
|
* @param lockRegistry to lock the tenant for auto assignment
|
||||||
* @param autoAssignExecutor
|
|
||||||
* to run a check as tenant
|
|
||||||
* @param lockRegistry
|
|
||||||
* to lock the tenant for auto assignment
|
|
||||||
* @return a new {@link AutoAssignChecker}
|
* @return a new {@link AutoAssignChecker}
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -945,11 +958,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
/**
|
/**
|
||||||
* {@link AutoActionCleanup} bean.
|
* {@link AutoActionCleanup} bean.
|
||||||
*
|
*
|
||||||
* @param deploymentManagement
|
* @param deploymentManagement Deployment management service
|
||||||
* Deployment management service
|
* @param configManagement Tenant configuration service
|
||||||
* @param configManagement
|
|
||||||
* Tenant configuration service
|
|
||||||
*
|
|
||||||
* @return a new {@link AutoActionCleanup} bean
|
* @return a new {@link AutoActionCleanup} bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -961,15 +971,10 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
/**
|
/**
|
||||||
* {@link AutoCleanupScheduler} bean.
|
* {@link AutoCleanupScheduler} bean.
|
||||||
*
|
*
|
||||||
* @param systemManagement
|
* @param systemManagement to find all tenants
|
||||||
* to find all tenants
|
* @param systemSecurityContext to run as system
|
||||||
* @param systemSecurityContext
|
* @param lockRegistry to lock the tenant for auto assignment
|
||||||
* to run as system
|
* @param cleanupTasks a list of cleanup tasks
|
||||||
* @param lockRegistry
|
|
||||||
* to lock the tenant for auto assignment
|
|
||||||
* @param cleanupTasks
|
|
||||||
* a list of cleanup tasks
|
|
||||||
*
|
|
||||||
* @return a new {@link AutoCleanupScheduler} bean
|
* @return a new {@link AutoCleanupScheduler} bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -988,12 +993,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
* Note: does not activate in test profile, otherwise it is hard to test the
|
* Note: does not activate in test profile, otherwise it is hard to test the
|
||||||
* rollout handling functionality.
|
* rollout handling functionality.
|
||||||
*
|
*
|
||||||
* @param systemManagement
|
* @param systemManagement to find all tenants
|
||||||
* to find all tenants
|
* @param rolloutHandler to run the rollout handler
|
||||||
* @param rolloutHandler
|
* @param systemSecurityContext to run as system
|
||||||
* to run the rollout handler
|
|
||||||
* @param systemSecurityContext
|
|
||||||
* to run as system
|
|
||||||
* @return a new {@link RolloutScheduler} bean.
|
* @return a new {@link RolloutScheduler} bean.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -1069,40 +1071,4 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
ArtifactEncryptionService artifactEncryptionService() {
|
ArtifactEncryptionService artifactEncryptionService() {
|
||||||
return ArtifactEncryptionService.getInstance();
|
return ArtifactEncryptionService.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public BeanPostProcessor entityManagerBeanPostProcessor(
|
|
||||||
@Autowired(required = false) final AccessController<JpaArtifact> artifactAccessController,
|
|
||||||
@Autowired(required = false) final AccessController<JpaSoftwareModuleType> softwareModuleTypeAccessController,
|
|
||||||
@Autowired(required = false) final AccessController<JpaSoftwareModule> softwareModuleAccessController,
|
|
||||||
@Autowired(required = false) final AccessController<JpaDistributionSetType> distributionSetTypeAccessController,
|
|
||||||
@Autowired(required = false) final AccessController<JpaDistributionSet> distributionSetAccessController,
|
|
||||||
@Autowired(required = false) final AccessController<JpaTargetType> targetTypeAccessControlManager,
|
|
||||||
@Autowired(required = false) final AccessController<JpaTarget> targetAccessControlManager,
|
|
||||||
@Autowired(required = false) final AccessController<JpaAction> actionAccessController) {
|
|
||||||
return new BeanPostProcessor() {
|
|
||||||
@Override
|
|
||||||
public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName)
|
|
||||||
throws BeansException {
|
|
||||||
if (bean instanceof LocalArtifactRepository repo) {
|
|
||||||
return repo.withACM(artifactAccessController);
|
|
||||||
} else if (bean instanceof SoftwareModuleTypeRepository repo) {
|
|
||||||
return repo.withACM(softwareModuleTypeAccessController);
|
|
||||||
} else if (bean instanceof SoftwareModuleRepository repo) {
|
|
||||||
return repo.withACM(softwareModuleAccessController);
|
|
||||||
} else if (bean instanceof DistributionSetTypeRepository repo) {
|
|
||||||
return repo.withACM(distributionSetTypeAccessController);
|
|
||||||
} else if (bean instanceof DistributionSetRepository repo) {
|
|
||||||
return repo.withACM(distributionSetAccessController);
|
|
||||||
} else if (bean instanceof TargetTypeRepository repo) {
|
|
||||||
return repo.withACM(targetTypeAccessControlManager);
|
|
||||||
} else if (bean instanceof TargetRepository repo) {
|
|
||||||
return repo.withACM(targetAccessControlManager);
|
|
||||||
} else if (bean instanceof ActionRepository repo) {
|
|
||||||
return repo.withACM(actionAccessController);
|
|
||||||
}
|
|
||||||
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,26 +26,10 @@ import org.springframework.context.annotation.Bean;
|
|||||||
*/
|
*/
|
||||||
public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator {
|
public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator {
|
||||||
|
|
||||||
|
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantAware tenantAware;
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of the {@link KeyGenerator} to generate a key based on
|
|
||||||
* either the {@code createInitialTenant} thread local and the
|
|
||||||
* {@link TenantAware}, but in case we are in a tenant creation with its default
|
|
||||||
* types we need to use as the tenant the current tenant which is currently
|
|
||||||
* created and not the one currently in the {@link TenantAware}.
|
|
||||||
*/
|
|
||||||
public class CurrentTenantKeyGenerator implements KeyGenerator {
|
|
||||||
@Override
|
|
||||||
public Object generate(final Object target, final Method method, final Object... params) {
|
|
||||||
String tenant = getTenantInCreation().orElseGet(() -> tenantAware.getCurrentTenant()).toUpperCase();
|
|
||||||
return SimpleKeyGenerator.generateKey(tenant, tenant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Bean
|
@Bean
|
||||||
public KeyGenerator currentTenantKeyGenerator() {
|
public KeyGenerator currentTenantKeyGenerator() {
|
||||||
@@ -55,7 +39,7 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG
|
|||||||
/**
|
/**
|
||||||
* Get the tenant which overwrites the actual tenant used by the
|
* Get the tenant which overwrites the actual tenant used by the
|
||||||
* {@linkplain #currentTenantKeyGenerator()}.
|
* {@linkplain #currentTenantKeyGenerator()}.
|
||||||
*
|
*
|
||||||
* @return A present optional in case that there is a tenant in the progress of
|
* @return A present optional in case that there is a tenant in the progress of
|
||||||
* creation.
|
* creation.
|
||||||
*/
|
*/
|
||||||
@@ -66,9 +50,8 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG
|
|||||||
/**
|
/**
|
||||||
* Overwrite the tenant used by the key generator in case that the tenant is in
|
* Overwrite the tenant used by the key generator in case that the tenant is in
|
||||||
* the process of creation.
|
* the process of creation.
|
||||||
*
|
*
|
||||||
* @param tenant
|
* @param tenant the tenant which should be used instead of the actual one.
|
||||||
* the tenant which should be used instead of the actual one.
|
|
||||||
*/
|
*/
|
||||||
public void setTenantInCreation(@NotNull String tenant) {
|
public void setTenantInCreation(@NotNull String tenant) {
|
||||||
createInitialTenant.set(Objects.requireNonNull(tenant));
|
createInitialTenant.set(Objects.requireNonNull(tenant));
|
||||||
@@ -81,4 +64,20 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG
|
|||||||
public void removeTenantInCreation() {
|
public void removeTenantInCreation() {
|
||||||
createInitialTenant.remove();
|
createInitialTenant.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the {@link KeyGenerator} to generate a key based on
|
||||||
|
* either the {@code createInitialTenant} thread local and the
|
||||||
|
* {@link TenantAware}, but in case we are in a tenant creation with its default
|
||||||
|
* types we need to use as the tenant the current tenant which is currently
|
||||||
|
* created and not the one currently in the {@link TenantAware}.
|
||||||
|
*/
|
||||||
|
public class CurrentTenantKeyGenerator implements KeyGenerator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object generate(final Object target, final Method method, final Object... params) {
|
||||||
|
String tenant = getTenantInCreation().orElseGet(() -> tenantAware.getCurrentTenant()).toUpperCase();
|
||||||
|
return SimpleKeyGenerator.generateKey(tenant, tenant);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link KeyGenerator} for tenant related caches.
|
* {@link KeyGenerator} for tenant related caches.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class TenantKeyGenerator implements KeyGenerator {
|
public class TenantKeyGenerator implements KeyGenerator {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import org.springframework.lang.Nullable;
|
|||||||
* additional restrictions (e.g. entity based) could be applied.
|
* additional restrictions (e.g. entity based) could be applied.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <b>Note</b>: Experimental, only
|
* <b>Note</b>: Experimental, only
|
||||||
*
|
*
|
||||||
* @param <T> the domain type the repository manages
|
* @param <T> the domain type the repository manages
|
||||||
*/
|
*/
|
||||||
public interface AccessController<T> {
|
public interface AccessController<T> {
|
||||||
@@ -33,16 +33,15 @@ public interface AccessController<T> {
|
|||||||
* Introduce a new specification to limit the access to a specific entity.
|
* Introduce a new specification to limit the access to a specific entity.
|
||||||
*
|
*
|
||||||
* @return a new specification limiting the access, if empty no access restrictions
|
* @return a new specification limiting the access, if empty no access restrictions
|
||||||
* are to be applied
|
* are to be applied
|
||||||
*/
|
*/
|
||||||
Optional<Specification<T>> getAccessRules(Operation operation);
|
Optional<Specification<T>> getAccessRules(Operation operation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append the resource limitation on an already existing specification.
|
* Append the resource limitation on an already existing specification.
|
||||||
*
|
*
|
||||||
* @param specification
|
* @param specification is the root specification which needs to be appended by the
|
||||||
* is the root specification which needs to be appended by the
|
* resource limitation
|
||||||
* resource limitation
|
|
||||||
* @return a new appended specification
|
* @return a new appended specification
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -55,18 +54,17 @@ public interface AccessController<T> {
|
|||||||
/**
|
/**
|
||||||
* Verify if the given {@link Operation} is permitted for the provided entity.
|
* Verify if the given {@link Operation} is permitted for the provided entity.
|
||||||
*
|
*
|
||||||
* @throws InsufficientPermissionException
|
* @throws InsufficientPermissionException if operation is not permitted for given entities
|
||||||
* if operation is not permitted for given entities
|
|
||||||
*/
|
*/
|
||||||
void assertOperationAllowed(final Operation operation, final T entity) throws InsufficientPermissionException;
|
void assertOperationAllowed(final Operation operation, final T entity) throws InsufficientPermissionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify if the given {@link Operation} is permitted for the provided entities.
|
* Verify if the given {@link Operation} is permitted for the provided entities.
|
||||||
*
|
*
|
||||||
* @throws InsufficientPermissionException
|
* @throws InsufficientPermissionException if operation is not permitted for given entities
|
||||||
* if operation is not permitted for given entities
|
|
||||||
*/
|
*/
|
||||||
default void assertOperationAllowed(final Operation operation, final Iterable<? extends T> entities) throws InsufficientPermissionException {
|
default void assertOperationAllowed(final Operation operation, final Iterable<? extends T> entities)
|
||||||
|
throws InsufficientPermissionException {
|
||||||
for (final T entity : entities) {
|
for (final T entity : entities) {
|
||||||
assertOperationAllowed(operation, entity);
|
assertOperationAllowed(operation, entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,7 @@ public class ExceptionMappingAspectHandler implements Ordered {
|
|||||||
* catch exceptions of the {@link TransactionManager} and wrap them to
|
* catch exceptions of the {@link TransactionManager} and wrap them to
|
||||||
* custom exceptions.
|
* custom exceptions.
|
||||||
*
|
*
|
||||||
* @param ex
|
* @param ex the thrown and catched exception
|
||||||
* the thrown and catched exception
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
@AfterThrowing(pointcut = "execution( * org.eclipse.hawkbit.repository.jpa.management.*Management.*(..))", throwing = "ex")
|
@AfterThrowing(pointcut = "execution( * org.eclipse.hawkbit.repository.jpa.management.*Management.*(..))", throwing = "ex")
|
||||||
@@ -103,6 +102,11 @@ public class ExceptionMappingAspectHandler implements Ordered {
|
|||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
private static Exception replaceWithCauseIfConstraintViolationException(final TransactionSystemException rex) {
|
private static Exception replaceWithCauseIfConstraintViolationException(final TransactionSystemException rex) {
|
||||||
Throwable exception = rex;
|
Throwable exception = rex;
|
||||||
do {
|
do {
|
||||||
@@ -115,9 +119,4 @@ public class ExceptionMappingAspectHandler implements Ordered {
|
|||||||
|
|
||||||
return rex;
|
return rex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOrder() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,15 +56,11 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param targetFilterQueryManagement
|
* @param targetFilterQueryManagement to get all target filter queries
|
||||||
* to get all target filter queries
|
* @param deploymentManagement to assign distribution sets to targets
|
||||||
* @param deploymentManagement
|
* @param transactionManager to run transactions
|
||||||
* to assign distribution sets to targets
|
* @param contextAware to handle the context
|
||||||
* @param transactionManager
|
|
||||||
* to run transactions
|
|
||||||
* @param contextAware
|
|
||||||
* to handle the context
|
|
||||||
*/
|
*/
|
||||||
protected AbstractAutoAssignExecutor(final TargetFilterQueryManagement targetFilterQueryManagement,
|
protected AbstractAutoAssignExecutor(final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||||
final DeploymentManagement deploymentManagement, final PlatformTransactionManager transactionManager,
|
final DeploymentManagement deploymentManagement, final PlatformTransactionManager transactionManager,
|
||||||
@@ -75,6 +71,12 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
|||||||
this.contextAware = contextAware;
|
this.contextAware = contextAware;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static String getAutoAssignmentInitiatedBy(final TargetFilterQuery targetFilterQuery) {
|
||||||
|
return StringUtils.hasText(targetFilterQuery.getAutoAssignInitiatedBy())
|
||||||
|
? targetFilterQuery.getAutoAssignInitiatedBy()
|
||||||
|
: targetFilterQuery.getCreatedBy();
|
||||||
|
}
|
||||||
|
|
||||||
protected DeploymentManagement getDeploymentManagement() {
|
protected DeploymentManagement getDeploymentManagement() {
|
||||||
return deploymentManagement;
|
return deploymentManagement;
|
||||||
}
|
}
|
||||||
@@ -100,17 +102,17 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
|||||||
filterQueries.forEach(filterQuery -> {
|
filterQueries.forEach(filterQuery -> {
|
||||||
try {
|
try {
|
||||||
filterQuery.getAccessControlContext().ifPresentOrElse(
|
filterQuery.getAccessControlContext().ifPresentOrElse(
|
||||||
context -> // has stored context - executes it with it
|
context -> // has stored context - executes it with it
|
||||||
contextAware.runInContext(
|
contextAware.runInContext(
|
||||||
context,
|
context,
|
||||||
() -> consumer.accept(filterQuery)),
|
() -> consumer.accept(filterQuery)),
|
||||||
() -> // has no stored context - executes it in the tenant & user scope
|
() -> // has no stored context - executes it in the tenant & user scope
|
||||||
contextAware.runAsTenantAsUser(
|
contextAware.runAsTenantAsUser(
|
||||||
contextAware.getCurrentTenant(),
|
contextAware.getCurrentTenant(),
|
||||||
getAutoAssignmentInitiatedBy(filterQuery), () -> {
|
getAutoAssignmentInitiatedBy(filterQuery), () -> {
|
||||||
consumer.accept(filterQuery);
|
consumer.accept(filterQuery);
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} catch (final RuntimeException ex) {
|
} catch (final RuntimeException ex) {
|
||||||
log.debug(
|
log.debug(
|
||||||
@@ -128,11 +130,9 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
|||||||
/**
|
/**
|
||||||
* Runs target assignments within a dedicated transaction for a given list of
|
* Runs target assignments within a dedicated transaction for a given list of
|
||||||
* controllerIDs
|
* controllerIDs
|
||||||
*
|
*
|
||||||
* @param targetFilterQuery
|
* @param targetFilterQuery the target filter query
|
||||||
* the target filter query
|
* @param controllerIds the controllerIDs
|
||||||
* @param controllerIds
|
|
||||||
* the controllerIDs
|
|
||||||
* @return count of targets
|
* @return count of targets
|
||||||
*/
|
*/
|
||||||
protected int runTransactionalAssignment(final TargetFilterQuery targetFilterQuery,
|
protected int runTransactionalAssignment(final TargetFilterQuery targetFilterQuery,
|
||||||
@@ -158,10 +158,8 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
|||||||
* Creates a list of {@link DeploymentRequest} for given list of controllerIds
|
* Creates a list of {@link DeploymentRequest} for given list of controllerIds
|
||||||
* and {@link TargetFilterQuery}
|
* and {@link TargetFilterQuery}
|
||||||
*
|
*
|
||||||
* @param controllerIds
|
* @param controllerIds list of controllerIds
|
||||||
* list of controllerIds
|
* @param filterQuery the query the targets have to match
|
||||||
* @param filterQuery
|
|
||||||
* the query the targets have to match
|
|
||||||
* @return list of deployment request
|
* @return list of deployment request
|
||||||
*/
|
*/
|
||||||
protected List<DeploymentRequest> mapToDeploymentRequests(final List<String> controllerIds,
|
protected List<DeploymentRequest> mapToDeploymentRequests(final List<String> controllerIds,
|
||||||
@@ -179,10 +177,4 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
|||||||
.setConfirmationRequired(filterQuery.isConfirmationRequired()).build())
|
.setConfirmationRequired(filterQuery.isConfirmationRequired()).build())
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String getAutoAssignmentInitiatedBy(final TargetFilterQuery targetFilterQuery) {
|
|
||||||
return StringUtils.hasText(targetFilterQuery.getAutoAssignInitiatedBy())
|
|
||||||
? targetFilterQuery.getAutoAssignInitiatedBy()
|
|
||||||
: targetFilterQuery.getCreatedBy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,16 +43,11 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
|||||||
/**
|
/**
|
||||||
* Instantiates a new auto assign checker
|
* Instantiates a new auto assign checker
|
||||||
*
|
*
|
||||||
* @param targetFilterQueryManagement
|
* @param targetFilterQueryManagement to get all target filter queries
|
||||||
* to get all target filter queries
|
* @param targetManagement to get targets
|
||||||
* @param targetManagement
|
* @param deploymentManagement to assign distribution sets to targets
|
||||||
* to get targets
|
* @param transactionManager to run transactions
|
||||||
* @param deploymentManagement
|
* @param contextAware to handle the context
|
||||||
* to assign distribution sets to targets
|
|
||||||
* @param transactionManager
|
|
||||||
* to run transactions
|
|
||||||
* @param contextAware
|
|
||||||
* to handle the context
|
|
||||||
*/
|
*/
|
||||||
public AutoAssignChecker(final TargetFilterQueryManagement targetFilterQueryManagement,
|
public AutoAssignChecker(final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||||
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
|
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
|
||||||
@@ -83,8 +78,7 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
|||||||
* them. Catches PersistenceException and own exceptions derived from
|
* them. Catches PersistenceException and own exceptions derived from
|
||||||
* AbstractServerRtException
|
* AbstractServerRtException
|
||||||
*
|
*
|
||||||
* @param targetFilterQuery
|
* @param targetFilterQuery the target filter query
|
||||||
* the target filter query
|
|
||||||
*/
|
*/
|
||||||
private void checkByTargetFilterQueryAndAssignDS(final TargetFilterQuery targetFilterQuery) {
|
private void checkByTargetFilterQueryAndAssignDS(final TargetFilterQuery targetFilterQuery) {
|
||||||
log.debug("Auto assign check call for tenant {} and target filter query id {} started",
|
log.debug("Auto assign check call for tenant {} and target filter query id {} started",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AutoAssignScheduler {
|
public class AutoAssignScheduler {
|
||||||
|
|
||||||
private static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.autoassign.scheduler.fixedDelay:2000}";
|
private static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.autoassign.scheduler.fixedDelay:2000}";
|
||||||
|
|
||||||
private final SystemManagement systemManagement;
|
private final SystemManagement systemManagement;
|
||||||
@@ -36,15 +36,11 @@ public class AutoAssignScheduler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new AutoAssignScheduler
|
* Instantiates a new AutoAssignScheduler
|
||||||
*
|
*
|
||||||
* @param systemManagement
|
* @param systemManagement to find all tenants
|
||||||
* to find all tenants
|
* @param systemSecurityContext to run as system
|
||||||
* @param systemSecurityContext
|
* @param autoAssignExecutor to run a check as tenant
|
||||||
* to run as system
|
* @param lockRegistry to acquire a lock per tenant
|
||||||
* @param autoAssignExecutor
|
|
||||||
* to run a check as tenant
|
|
||||||
* @param lockRegistry
|
|
||||||
* to acquire a lock per tenant
|
|
||||||
*/
|
*/
|
||||||
public AutoAssignScheduler(final SystemManagement systemManagement,
|
public AutoAssignScheduler(final SystemManagement systemManagement,
|
||||||
final SystemSecurityContext systemSecurityContext, final AutoAssignExecutor autoAssignExecutor,
|
final SystemSecurityContext systemSecurityContext, final AutoAssignExecutor autoAssignExecutor,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
|||||||
* actions which are in a certain {@link Action.Status}. It is recommended to
|
* actions which are in a certain {@link Action.Status}. It is recommended to
|
||||||
* only clean up actions which have terminated already (i.e. actions in status
|
* only clean up actions which have terminated already (i.e. actions in status
|
||||||
* CANCELLED or ERROR).
|
* CANCELLED or ERROR).
|
||||||
*
|
*
|
||||||
* The cleanup task can be enabled /disabled and configured on a per tenant
|
* The cleanup task can be enabled /disabled and configured on a per tenant
|
||||||
* basis.
|
* basis.
|
||||||
*/
|
*/
|
||||||
@@ -49,11 +49,9 @@ public class AutoActionCleanup implements CleanupTask {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the action cleanup handler.
|
* Constructs the action cleanup handler.
|
||||||
*
|
*
|
||||||
* @param deploymentMgmt
|
* @param deploymentMgmt The {@link DeploymentManagement} to operate on.
|
||||||
* The {@link DeploymentManagement} to operate on.
|
* @param configMgmt The {@link TenantConfigurationManagement} service.
|
||||||
* @param configMgmt
|
|
||||||
* The {@link TenantConfigurationManagement} service.
|
|
||||||
*/
|
*/
|
||||||
public AutoActionCleanup(final DeploymentManagement deploymentMgmt,
|
public AutoActionCleanup(final DeploymentManagement deploymentMgmt,
|
||||||
final TenantConfigurationManagement configMgmt) {
|
final TenantConfigurationManagement configMgmt) {
|
||||||
|
|||||||
@@ -36,15 +36,11 @@ public class AutoCleanupScheduler {
|
|||||||
/**
|
/**
|
||||||
* Constructs the cleanup schedulers and initializes it with a set of
|
* Constructs the cleanup schedulers and initializes it with a set of
|
||||||
* cleanup handlers.
|
* cleanup handlers.
|
||||||
*
|
*
|
||||||
* @param systemManagement
|
* @param systemManagement Management APIs to invoke actions in a certain tenant context.
|
||||||
* Management APIs to invoke actions in a certain tenant context.
|
* @param systemSecurityContext The system security context.
|
||||||
* @param systemSecurityContext
|
* @param lockRegistry A registry for shared locks.
|
||||||
* The system security context.
|
* @param cleanupTasks A list of cleanup tasks.
|
||||||
* @param lockRegistry
|
|
||||||
* A registry for shared locks.
|
|
||||||
* @param cleanupTasks
|
|
||||||
* A list of cleanup tasks.
|
|
||||||
*/
|
*/
|
||||||
public AutoCleanupScheduler(final SystemManagement systemManagement,
|
public AutoCleanupScheduler(final SystemManagement systemManagement,
|
||||||
final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry,
|
final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry,
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import org.eclipse.hawkbit.repository.model.ActionStatus;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link ActionStatus}.
|
* Builder implementation for {@link ActionStatus}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaActionStatusBuilder implements ActionStatusBuilder {
|
public class JpaActionStatusBuilder implements ActionStatusBuilder {
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaActionStatusCreate extends AbstractActionStatusCreate<ActionStatusCreate>
|
public class JpaActionStatusCreate extends AbstractActionStatusCreate<ActionStatusCreate>
|
||||||
implements ActionStatusCreate {
|
implements ActionStatusCreate {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link DistributionSet}.
|
* Builder implementation for {@link DistributionSet}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaDistributionSetBuilder implements DistributionSetBuilder {
|
public class JpaDistributionSetBuilder implements DistributionSetBuilder {
|
||||||
|
|
||||||
|
|||||||
@@ -27,16 +27,14 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaDistributionSetCreate extends AbstractDistributionSetUpdateCreate<DistributionSetCreate>
|
public class JpaDistributionSetCreate extends AbstractDistributionSetUpdateCreate<DistributionSetCreate>
|
||||||
implements DistributionSetCreate {
|
implements DistributionSetCreate {
|
||||||
|
|
||||||
@ValidString
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||||
private final SoftwareModuleManagement softwareModuleManagement;
|
private final SoftwareModuleManagement softwareModuleManagement;
|
||||||
|
@ValidString
|
||||||
|
private String type;
|
||||||
|
|
||||||
JpaDistributionSetCreate(final DistributionSetTypeManagement distributionSetTypeManagement,
|
JpaDistributionSetCreate(final DistributionSetTypeManagement distributionSetTypeManagement,
|
||||||
final SoftwareModuleManagement softwareManagement) {
|
final SoftwareModuleManagement softwareManagement) {
|
||||||
@@ -44,6 +42,12 @@ public class JpaDistributionSetCreate extends AbstractDistributionSetUpdateCreat
|
|||||||
this.softwareModuleManagement = softwareManagement;
|
this.softwareModuleManagement = softwareManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DistributionSetCreate type(final String type) {
|
||||||
|
this.type = StringUtils.trimWhitespace(type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaDistributionSet build() {
|
public JpaDistributionSet build() {
|
||||||
return new JpaDistributionSet(name, version, description,
|
return new JpaDistributionSet(name, version, description,
|
||||||
@@ -52,12 +56,6 @@ public class JpaDistributionSetCreate extends AbstractDistributionSetUpdateCreat
|
|||||||
Optional.ofNullable(requiredMigrationStep).orElse(Boolean.FALSE));
|
Optional.ofNullable(requiredMigrationStep).orElse(Boolean.FALSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DistributionSetCreate type(final String type) {
|
|
||||||
this.type = StringUtils.trimWhitespace(type);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link DistributionSetType}.
|
* Builder implementation for {@link DistributionSetType}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaDistributionSetTypeBuilder implements DistributionSetTypeBuilder {
|
public class JpaDistributionSetTypeBuilder implements DistributionSetTypeBuilder {
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import org.springframework.util.CollectionUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaDistributionSetTypeCreate extends AbstractDistributionSetTypeUpdateCreate<DistributionSetTypeCreate>
|
public class JpaDistributionSetTypeCreate extends AbstractDistributionSetTypeUpdateCreate<DistributionSetTypeCreate>
|
||||||
implements DistributionSetTypeCreate {
|
implements DistributionSetTypeCreate {
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import org.eclipse.hawkbit.repository.model.Rollout;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link Rollout}.
|
* Builder implementation for {@link Rollout}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaRolloutBuilder implements RolloutBuilder {
|
public class JpaRolloutBuilder implements RolloutBuilder {
|
||||||
|
|
||||||
private final DistributionSetManagement distributionSetManagement;
|
private final DistributionSetManagement distributionSetManagement;
|
||||||
|
|
||||||
public JpaRolloutBuilder(final DistributionSetManagement distributionSetManagement) {
|
public JpaRolloutBuilder(final DistributionSetManagement distributionSetManagement) {
|
||||||
|
|||||||
@@ -9,8 +9,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import jakarta.validation.constraints.Max;
|
import jakarta.validation.constraints.Max;
|
||||||
import jakarta.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||||
import org.eclipse.hawkbit.repository.ValidString;
|
import org.eclipse.hawkbit.repository.ValidString;
|
||||||
import org.eclipse.hawkbit.repository.builder.AbstractNamedEntityBuilder;
|
import org.eclipse.hawkbit.repository.builder.AbstractNamedEntityBuilder;
|
||||||
@@ -20,12 +23,8 @@ import org.eclipse.hawkbit.repository.model.Action;
|
|||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate> implements RolloutCreate {
|
public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate> implements RolloutCreate {
|
||||||
|
|
||||||
private final DistributionSetManagement distributionSetManagement;
|
|
||||||
|
|
||||||
protected Long distributionSetId;
|
protected Long distributionSetId;
|
||||||
@ValidString
|
@ValidString
|
||||||
protected String targetFilterQuery;
|
protected String targetFilterQuery;
|
||||||
@@ -35,12 +34,13 @@ public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate>
|
|||||||
@Min(Action.WEIGHT_MIN)
|
@Min(Action.WEIGHT_MIN)
|
||||||
@Max(Action.WEIGHT_MAX)
|
@Max(Action.WEIGHT_MAX)
|
||||||
protected Integer weight;
|
protected Integer weight;
|
||||||
|
private final DistributionSetManagement distributionSetManagement;
|
||||||
private boolean dynamic;
|
private boolean dynamic;
|
||||||
|
|
||||||
JpaRolloutCreate(final DistributionSetManagement distributionSetManagement) {
|
JpaRolloutCreate(final DistributionSetManagement distributionSetManagement) {
|
||||||
this.distributionSetManagement = distributionSetManagement;
|
this.distributionSetManagement = distributionSetManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DistributionSet} of rollout
|
* {@link DistributionSet} of rollout
|
||||||
*
|
*
|
||||||
@@ -62,6 +62,7 @@ public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate>
|
|||||||
this.targetFilterQuery = StringUtils.trimWhitespace(targetFilterQuery);
|
this.targetFilterQuery = StringUtils.trimWhitespace(targetFilterQuery);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Action.ActionType} used for {@link Action}s
|
* {@link Action.ActionType} used for {@link Action}s
|
||||||
*
|
*
|
||||||
@@ -95,6 +96,11 @@ public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate>
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RolloutCreate dynamic(final boolean dynamic) {
|
||||||
|
this.dynamic = dynamic;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set start of the Rollout
|
* Set start of the Rollout
|
||||||
*
|
*
|
||||||
@@ -106,31 +112,6 @@ public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate>
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Long> getDistributionSetId() {
|
|
||||||
return Optional.ofNullable(distributionSetId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<Action.ActionType> getActionType() {
|
|
||||||
return Optional.ofNullable(actionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<Long> getForcedTime() {
|
|
||||||
return Optional.ofNullable(forcedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<Integer> getWeight() {
|
|
||||||
return Optional.ofNullable(weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<Long> getStartAt() {
|
|
||||||
return Optional.ofNullable(startAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RolloutCreate dynamic(final boolean dynamic) {
|
|
||||||
this.dynamic = dynamic;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaRollout build() {
|
public JpaRollout build() {
|
||||||
final JpaRollout rollout = new JpaRollout();
|
final JpaRollout rollout = new JpaRollout();
|
||||||
@@ -153,4 +134,24 @@ public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate>
|
|||||||
|
|
||||||
return rollout;
|
return rollout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getDistributionSetId() {
|
||||||
|
return Optional.ofNullable(distributionSetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Action.ActionType> getActionType() {
|
||||||
|
return Optional.ofNullable(actionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getForcedTime() {
|
||||||
|
return Optional.ofNullable(forcedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getWeight() {
|
||||||
|
return Optional.ofNullable(weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getStartAt() {
|
||||||
|
return Optional.ofNullable(startAt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,9 +15,9 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link RolloutGroup}.
|
* Builder implementation for {@link RolloutGroup}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaRolloutGroupBuilder implements RolloutGroupBuilder {
|
public class JpaRolloutGroupBuilder implements RolloutGroupBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RolloutGroupCreate create() {
|
public RolloutGroupCreate create() {
|
||||||
return new JpaRolloutGroupCreate();
|
return new JpaRolloutGroupCreate();
|
||||||
|
|||||||
@@ -18,6 +18,51 @@ import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
|||||||
public class JpaRolloutGroupCreate extends AbstractRolloutGroupCreate<RolloutGroupCreate>
|
public class JpaRolloutGroupCreate extends AbstractRolloutGroupCreate<RolloutGroupCreate>
|
||||||
implements RolloutGroupCreate {
|
implements RolloutGroupCreate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Success And Error conditions for the rollout group
|
||||||
|
*
|
||||||
|
* @param group The Rollout group
|
||||||
|
* @param conditions The Rollout Success and Error Conditions
|
||||||
|
*/
|
||||||
|
public static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group,
|
||||||
|
final RolloutGroupConditions conditions) {
|
||||||
|
addSuccessAndErrorConditionsAndActions(group, conditions.getSuccessCondition(),
|
||||||
|
conditions.getSuccessConditionExp(), conditions.getSuccessAction(), conditions.getSuccessActionExp(),
|
||||||
|
conditions.getErrorCondition(), conditions.getErrorConditionExp(), conditions.getErrorAction(),
|
||||||
|
conditions.getErrorActionExp());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Success And Error conditions for the rollout group
|
||||||
|
*
|
||||||
|
* @param group The Rollout group
|
||||||
|
* @param successCondition The Rollout group success condition
|
||||||
|
* @param successConditionExp The Rollout group success expression
|
||||||
|
* @param successAction The Rollout group success action
|
||||||
|
* @param successActionExp The Rollout group success action expression
|
||||||
|
* @param errorCondition The Rollout group error condition
|
||||||
|
* @param errorConditionExp The Rollout group error expression
|
||||||
|
* @param errorAction The Rollout group error action
|
||||||
|
* @param errorActionExp The Rollout group error action expression
|
||||||
|
*/
|
||||||
|
public static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group,
|
||||||
|
final RolloutGroup.RolloutGroupSuccessCondition successCondition, final String successConditionExp,
|
||||||
|
final RolloutGroup.RolloutGroupSuccessAction successAction, final String successActionExp,
|
||||||
|
final RolloutGroup.RolloutGroupErrorCondition errorCondition, final String errorConditionExp,
|
||||||
|
final RolloutGroup.RolloutGroupErrorAction errorAction, final String errorActionExp) {
|
||||||
|
group.setSuccessCondition(successCondition);
|
||||||
|
group.setSuccessConditionExp(successConditionExp);
|
||||||
|
|
||||||
|
group.setSuccessAction(successAction);
|
||||||
|
group.setSuccessActionExp(successActionExp);
|
||||||
|
|
||||||
|
group.setErrorCondition(errorCondition);
|
||||||
|
group.setErrorConditionExp(errorConditionExp);
|
||||||
|
|
||||||
|
group.setErrorAction(errorAction);
|
||||||
|
group.setErrorActionExp(errorActionExp);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaRolloutGroup build() {
|
public JpaRolloutGroup build() {
|
||||||
final JpaRolloutGroup group = new JpaRolloutGroup();
|
final JpaRolloutGroup group = new JpaRolloutGroup();
|
||||||
@@ -40,60 +85,4 @@ public class JpaRolloutGroupCreate extends AbstractRolloutGroupCreate<RolloutGro
|
|||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Success And Error conditions for the rollout group
|
|
||||||
*
|
|
||||||
* @param group
|
|
||||||
* The Rollout group
|
|
||||||
* @param conditions
|
|
||||||
* The Rollout Success and Error Conditions
|
|
||||||
*/
|
|
||||||
public static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group,
|
|
||||||
final RolloutGroupConditions conditions) {
|
|
||||||
addSuccessAndErrorConditionsAndActions(group, conditions.getSuccessCondition(),
|
|
||||||
conditions.getSuccessConditionExp(), conditions.getSuccessAction(), conditions.getSuccessActionExp(),
|
|
||||||
conditions.getErrorCondition(), conditions.getErrorConditionExp(), conditions.getErrorAction(),
|
|
||||||
conditions.getErrorActionExp());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Success And Error conditions for the rollout group
|
|
||||||
*
|
|
||||||
* @param group
|
|
||||||
* The Rollout group
|
|
||||||
* @param successCondition
|
|
||||||
* The Rollout group success condition
|
|
||||||
* @param successConditionExp
|
|
||||||
* The Rollout group success expression
|
|
||||||
* @param successAction
|
|
||||||
* The Rollout group success action
|
|
||||||
* @param successActionExp
|
|
||||||
* The Rollout group success action expression
|
|
||||||
* @param errorCondition
|
|
||||||
* The Rollout group error condition
|
|
||||||
* @param errorConditionExp
|
|
||||||
* The Rollout group error expression
|
|
||||||
* @param errorAction
|
|
||||||
* The Rollout group error action
|
|
||||||
* @param errorActionExp
|
|
||||||
* The Rollout group error action expression
|
|
||||||
*/
|
|
||||||
public static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group,
|
|
||||||
final RolloutGroup.RolloutGroupSuccessCondition successCondition, final String successConditionExp,
|
|
||||||
final RolloutGroup.RolloutGroupSuccessAction successAction, final String successActionExp,
|
|
||||||
final RolloutGroup.RolloutGroupErrorCondition errorCondition, final String errorConditionExp,
|
|
||||||
final RolloutGroup.RolloutGroupErrorAction errorAction, final String errorActionExp) {
|
|
||||||
group.setSuccessCondition(successCondition);
|
|
||||||
group.setSuccessConditionExp(successConditionExp);
|
|
||||||
|
|
||||||
group.setSuccessAction(successAction);
|
|
||||||
group.setSuccessActionExp(successActionExp);
|
|
||||||
|
|
||||||
group.setErrorCondition(errorCondition);
|
|
||||||
group.setErrorConditionExp(errorConditionExp);
|
|
||||||
|
|
||||||
group.setErrorAction(errorAction);
|
|
||||||
group.setErrorActionExp(errorActionExp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link SoftwareModule}.
|
* Builder implementation for {@link SoftwareModule}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaSoftwareModuleBuilder implements SoftwareModuleBuilder {
|
public class JpaSoftwareModuleBuilder implements SoftwareModuleBuilder {
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaSoftwareModuleCreate extends AbstractSoftwareModuleUpdateCreate<SoftwareModuleCreate>
|
public class JpaSoftwareModuleCreate extends AbstractSoftwareModuleUpdateCreate<SoftwareModuleCreate>
|
||||||
implements SoftwareModuleCreate {
|
implements SoftwareModuleCreate {
|
||||||
@@ -39,16 +38,16 @@ public class JpaSoftwareModuleCreate extends AbstractSoftwareModuleUpdateCreate<
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEncrypted() {
|
|
||||||
return encrypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaSoftwareModule build() {
|
public JpaSoftwareModule build() {
|
||||||
return new JpaSoftwareModule(getSoftwareModuleTypeFromKeyString(type), name, version, description, vendor,
|
return new JpaSoftwareModule(getSoftwareModuleTypeFromKeyString(type), name, version, description, vendor,
|
||||||
encrypted);
|
encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEncrypted() {
|
||||||
|
return encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
private SoftwareModuleType getSoftwareModuleTypeFromKeyString(final String type) {
|
private SoftwareModuleType getSoftwareModuleTypeFromKeyString(final String type) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new ValidationException("type cannot be null");
|
throw new ValidationException("type cannot be null");
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link SoftwareModuleMetadata}.
|
* Builder implementation for {@link SoftwareModuleMetadata}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaSoftwareModuleMetadataBuilder implements SoftwareModuleMetadataBuilder {
|
public class JpaSoftwareModuleMetadataBuilder implements SoftwareModuleMetadataBuilder {
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaSoftwareModuleMetadataCreate
|
public class JpaSoftwareModuleMetadataCreate
|
||||||
extends AbstractSoftwareModuleMetadataUpdateCreate<SoftwareModuleMetadataCreate>
|
extends AbstractSoftwareModuleMetadataUpdateCreate<SoftwareModuleMetadataCreate>
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link SoftwareModuleType}.
|
* Builder implementation for {@link SoftwareModuleType}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaSoftwareModuleTypeBuilder implements SoftwareModuleTypeBuilder {
|
public class JpaSoftwareModuleTypeBuilder implements SoftwareModuleTypeBuilder {
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaSoftwareModuleTypeCreate extends AbstractSoftwareModuleTypeUpdateCreate<SoftwareModuleTypeCreate>
|
public class JpaSoftwareModuleTypeCreate extends AbstractSoftwareModuleTypeUpdateCreate<SoftwareModuleTypeCreate>
|
||||||
implements SoftwareModuleTypeCreate {
|
implements SoftwareModuleTypeCreate {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import org.eclipse.hawkbit.repository.model.Tag;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link Tag}.
|
* Builder implementation for {@link Tag}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTagBuilder implements TagBuilder {
|
public class JpaTagBuilder implements TagBuilder {
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import org.eclipse.hawkbit.repository.model.Tag;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTagCreate extends AbstractTagUpdateCreate<TagCreate> implements TagCreate {
|
public class JpaTagCreate extends AbstractTagUpdateCreate<TagCreate> implements TagCreate {
|
||||||
|
|
||||||
JpaTagCreate() {
|
JpaTagCreate() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,13 @@ import org.eclipse.hawkbit.repository.model.Target;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link Target}.
|
* Builder implementation for {@link Target}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTargetBuilder implements TargetBuilder {
|
public class JpaTargetBuilder implements TargetBuilder {
|
||||||
|
|
||||||
final private TargetTypeManagement targetTypeManagement;
|
final private TargetTypeManagement targetTypeManagement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param targetTypeManagement
|
* @param targetTypeManagement Target type management
|
||||||
* Target type management
|
|
||||||
*/
|
*/
|
||||||
public JpaTargetBuilder(TargetTypeManagement targetTypeManagement) {
|
public JpaTargetBuilder(TargetTypeManagement targetTypeManagement) {
|
||||||
this.targetTypeManagement = targetTypeManagement;
|
this.targetTypeManagement = targetTypeManagement;
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> implements TargetCreate {
|
public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> implements TargetCreate {
|
||||||
|
|
||||||
@@ -29,8 +28,7 @@ public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> im
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param targetTypeManagement
|
* @param targetTypeManagement Target type management
|
||||||
* Target type management
|
|
||||||
*/
|
*/
|
||||||
JpaTargetCreate(final TargetTypeManagement targetTypeManagement) {
|
JpaTargetCreate(final TargetTypeManagement targetTypeManagement) {
|
||||||
super(null);
|
super(null);
|
||||||
@@ -51,7 +49,7 @@ public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> im
|
|||||||
target.setName(name);
|
target.setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetTypeId != null){
|
if (targetTypeId != null) {
|
||||||
TargetType targetType = targetTypeManagement.get(targetTypeId)
|
TargetType targetType = targetTypeManagement.get(targetTypeId)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId));
|
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId));
|
||||||
target.setTargetType(targetType);
|
target.setTargetType(targetType);
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link TargetFilterQuery}.
|
* Builder implementation for {@link TargetFilterQuery}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTargetFilterQueryBuilder implements TargetFilterQueryBuilder {
|
public class JpaTargetFilterQueryBuilder implements TargetFilterQueryBuilder {
|
||||||
|
|
||||||
private final DistributionSetManagement distributionSetManagement;
|
private final DistributionSetManagement distributionSetManagement;
|
||||||
|
|
||||||
public JpaTargetFilterQueryBuilder(final DistributionSetManagement distributionSetManagement) {
|
public JpaTargetFilterQueryBuilder(final DistributionSetManagement distributionSetManagement) {
|
||||||
@@ -33,14 +33,14 @@ public class JpaTargetFilterQueryBuilder implements TargetFilterQueryBuilder {
|
|||||||
return new GenericTargetFilterQueryUpdate(id);
|
return new GenericTargetFilterQueryUpdate(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetFilterQueryCreate create() {
|
|
||||||
return new JpaTargetFilterQueryCreate(distributionSetManagement);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AutoAssignDistributionSetUpdate updateAutoAssign(final long id) {
|
public AutoAssignDistributionSetUpdate updateAutoAssign(final long id) {
|
||||||
return new AutoAssignDistributionSetUpdate(id);
|
return new AutoAssignDistributionSetUpdate(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TargetFilterQueryCreate create() {
|
||||||
|
return new JpaTargetFilterQueryCreate(distributionSetManagement);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTargetFilterQueryCreate extends AbstractTargetFilterQueryUpdateCreate<TargetFilterQueryCreate>
|
public class JpaTargetFilterQueryCreate extends AbstractTargetFilterQueryUpdateCreate<TargetFilterQueryCreate>
|
||||||
implements TargetFilterQueryCreate {
|
implements TargetFilterQueryCreate {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
|
||||||
import org.eclipse.hawkbit.repository.builder.GenericTargetTypeUpdate;
|
import org.eclipse.hawkbit.repository.builder.GenericTargetTypeUpdate;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||||
@@ -19,16 +18,15 @@ import org.eclipse.hawkbit.repository.model.TargetType;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link TargetType}.
|
* Builder implementation for {@link TargetType}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTargetTypeBuilder implements TargetTypeBuilder {
|
public class JpaTargetTypeBuilder implements TargetTypeBuilder {
|
||||||
|
|
||||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param distributionSetTypeManagement
|
* @param distributionSetTypeManagement Distribution set type management
|
||||||
* Distribution set type management
|
|
||||||
*/
|
*/
|
||||||
public JpaTargetTypeBuilder(DistributionSetTypeManagement distributionSetTypeManagement) {
|
public JpaTargetTypeBuilder(DistributionSetTypeManagement distributionSetTypeManagement) {
|
||||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||||
import org.eclipse.hawkbit.repository.builder.AbstractTargetTypeUpdateCreate;
|
import org.eclipse.hawkbit.repository.builder.AbstractTargetTypeUpdateCreate;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||||
@@ -19,12 +22,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
|||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/build implementation.
|
* Create/build implementation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class JpaTargetTypeCreate extends AbstractTargetTypeUpdateCreate<TargetTypeCreate>
|
public class JpaTargetTypeCreate extends AbstractTargetTypeUpdateCreate<TargetTypeCreate>
|
||||||
implements TargetTypeCreate {
|
implements TargetTypeCreate {
|
||||||
@@ -34,8 +33,7 @@ public class JpaTargetTypeCreate extends AbstractTargetTypeUpdateCreate<TargetTy
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param distributionSetTypeManagement
|
* @param distributionSetTypeManagement Distribution set type management
|
||||||
* Distribution set type management
|
|
||||||
*/
|
*/
|
||||||
JpaTargetTypeCreate(final DistributionSetTypeManagement distributionSetTypeManagement) {
|
JpaTargetTypeCreate(final DistributionSetTypeManagement distributionSetTypeManagement) {
|
||||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
|||||||
* {@link JpaTransactionManager} that sets the
|
* {@link JpaTransactionManager} that sets the
|
||||||
* {@link TenantAware#getCurrentTenant()} in the eclipselink session. This has
|
* {@link TenantAware#getCurrentTenant()} in the eclipselink session. This has
|
||||||
* to be done in eclipselink after a {@link Transaction} has been started.
|
* to be done in eclipselink after a {@link Transaction} has been started.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class MultiTenantJpaTransactionManager extends JpaTransactionManager {
|
public class MultiTenantJpaTransactionManager extends JpaTransactionManager {
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSynchronizationAdapter
|
public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSynchronizationAdapter
|
||||||
implements AfterTransactionCommitExecutor {
|
implements AfterTransactionCommitExecutor {
|
||||||
|
|
||||||
private static final ThreadLocal<List<Runnable>> THREAD_LOCAL_RUNNABLES = new ThreadLocal<>();
|
private static final ThreadLocal<List<Runnable>> THREAD_LOCAL_RUNNABLES = new ThreadLocal<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -42,6 +42,14 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({ "squid:S1217" })
|
||||||
|
public void afterCompletion(final int status) {
|
||||||
|
final String transactionStatus = status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK";
|
||||||
|
log.debug("Transaction completed after commit with status {}", transactionStatus);
|
||||||
|
THREAD_LOCAL_RUNNABLES.remove();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
// Exception squid:S1217 - we want to run this synchronous
|
// Exception squid:S1217 - we want to run this synchronous
|
||||||
@SuppressWarnings("squid:S1217")
|
@SuppressWarnings("squid:S1217")
|
||||||
@@ -62,12 +70,4 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn
|
|||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings({ "squid:S1217" })
|
|
||||||
public void afterCompletion(final int status) {
|
|
||||||
final String transactionStatus = status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK";
|
|
||||||
log.debug("Transaction completed after commit with status {}", transactionStatus);
|
|
||||||
THREAD_LOCAL_RUNNABLES.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,8 @@
|
|||||||
package org.eclipse.hawkbit.repository.jpa.executor;
|
package org.eclipse.hawkbit.repository.jpa.executor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* A interface to register a runnable, which will be executed after a successful
|
* A interface to register a runnable, which will be executed after a successful
|
||||||
* spring transaction.
|
* spring transaction.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface AfterTransactionCommitExecutor {
|
public interface AfterTransactionCommitExecutor {
|
||||||
@@ -21,9 +19,8 @@ public interface AfterTransactionCommitExecutor {
|
|||||||
/**
|
/**
|
||||||
* Register a runnable which will be executed after a successful spring
|
* Register a runnable which will be executed after a successful spring
|
||||||
* transaction.
|
* transaction.
|
||||||
*
|
*
|
||||||
* @param runnable
|
* @param runnable the after commit runnable
|
||||||
* the after commit runnable
|
|
||||||
*/
|
*/
|
||||||
void afterCommit(Runnable runnable);
|
void afterCommit(Runnable runnable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import java.util.Set;
|
|||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import jakarta.persistence.criteria.JoinType;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||||
@@ -48,8 +50,6 @@ import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
|||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.JoinType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DistributionSet} to {@link Target} assignment strategy as utility for
|
* {@link DistributionSet} to {@link Target} assignment strategy as utility for
|
||||||
* {@link JpaDeploymentManagement}.
|
* {@link JpaDeploymentManagement}.
|
||||||
@@ -68,10 +68,10 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
private final RepositoryProperties repositoryProperties;
|
private final RepositoryProperties repositoryProperties;
|
||||||
|
|
||||||
AbstractDsAssignmentStrategy(final TargetRepository targetRepository,
|
AbstractDsAssignmentStrategy(final TargetRepository targetRepository,
|
||||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||||
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties) {
|
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties) {
|
||||||
this.targetRepository = targetRepository;
|
this.targetRepository = targetRepository;
|
||||||
this.afterCommit = afterCommit;
|
this.afterCommit = afterCommit;
|
||||||
this.eventPublisherHolder = eventPublisherHolder;
|
this.eventPublisherHolder = eventPublisherHolder;
|
||||||
@@ -83,63 +83,47 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
this.repositoryProperties = repositoryProperties;
|
this.repositoryProperties = repositoryProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
||||||
* Find targets to be considered for assignment.
|
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
||||||
*
|
final Optional<JpaTarget> optTarget = targets.stream()
|
||||||
* @param controllerIDs
|
.filter(t -> t.getControllerId().equals(targetWithActionType.getControllerId())).findFirst();
|
||||||
* as provided by repository caller
|
|
||||||
* @param distributionSetId
|
|
||||||
* to assign
|
|
||||||
* @return list of targets up to {@link Constants#MAX_ENTRIES_IN_STATEMENT}
|
|
||||||
*/
|
|
||||||
abstract List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long distributionSetId);
|
|
||||||
|
|
||||||
/**
|
// create the action
|
||||||
*
|
return optTarget.map(target -> {
|
||||||
* @param set
|
assertActionsPerTargetQuota(target, 1);
|
||||||
* @param targets
|
final JpaAction actionForTarget = new JpaAction();
|
||||||
*/
|
actionForTarget.setActionType(targetWithActionType.getActionType());
|
||||||
abstract void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets);
|
actionForTarget.setForcedTime(targetWithActionType.getForceTime());
|
||||||
|
actionForTarget.setWeight(
|
||||||
|
targetWithActionType.getWeight() == null ?
|
||||||
|
repositoryProperties.getActionWeightIfAbsent() : targetWithActionType.getWeight());
|
||||||
|
actionForTarget.setActive(true);
|
||||||
|
actionForTarget.setTarget(target);
|
||||||
|
actionForTarget.setDistributionSet(set);
|
||||||
|
actionForTarget.setMaintenanceWindowSchedule(targetWithActionType.getMaintenanceSchedule());
|
||||||
|
actionForTarget.setMaintenanceWindowDuration(targetWithActionType.getMaintenanceWindowDuration());
|
||||||
|
actionForTarget.setMaintenanceWindowTimeZone(targetWithActionType.getMaintenanceWindowTimeZone());
|
||||||
|
actionForTarget.setInitiatedBy(initiatedBy);
|
||||||
|
return actionForTarget;
|
||||||
|
}).orElseGet(() -> {
|
||||||
|
log.warn("Cannot find target for targetWithActionType '{}'.", targetWithActionType.getControllerId());
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
||||||
* Update status and DS fields of given target.
|
final JpaActionStatus actionStatus = new JpaActionStatus();
|
||||||
*
|
actionStatus.setAction(action);
|
||||||
* @param distributionSet
|
actionStatus.setOccurredAt(action.getCreatedAt());
|
||||||
* to set
|
|
||||||
* @param targetIds
|
|
||||||
* to change
|
|
||||||
* @param currentUser
|
|
||||||
* for auditing
|
|
||||||
*/
|
|
||||||
abstract void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet distributionSet,
|
|
||||||
final List<List<Long>> targetIds, final String currentUser);
|
|
||||||
|
|
||||||
/**
|
if (StringUtils.hasText(actionMessage)) {
|
||||||
* Cancels actions that can be canceled (i.e.
|
actionStatus.addMessage(actionMessage);
|
||||||
* {@link DistributionSet#isRequiredMigrationStep() is <code>false</code>})
|
} else {
|
||||||
* as a result of the new assignment and returns all {@link Target}s where
|
actionStatus.addMessage(getActionMessage(action));
|
||||||
* such actions existed.
|
}
|
||||||
*
|
|
||||||
* @param targetIds
|
|
||||||
* to cancel actions for
|
|
||||||
* @return {@link Set} of {@link Target#getId()}s
|
|
||||||
*/
|
|
||||||
abstract Set<Long> cancelActiveActions(List<List<Long>> targetIds);
|
|
||||||
|
|
||||||
/**
|
return actionStatus;
|
||||||
* Cancels actions that can be canceled (i.e.
|
}
|
||||||
* {@link DistributionSet#isRequiredMigrationStep() is <code>false</code>})
|
|
||||||
* as a result of the new assignment and returns all {@link Target}s where
|
|
||||||
* such actions existed.
|
|
||||||
*
|
|
||||||
* @param targetIds
|
|
||||||
* to cancel actions for
|
|
||||||
*/
|
|
||||||
abstract void closeActiveActions(List<List<Long>> targetIds);
|
|
||||||
|
|
||||||
abstract void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult);
|
|
||||||
|
|
||||||
abstract void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults);
|
|
||||||
|
|
||||||
protected void sendTargetUpdatedEvent(final JpaTarget target) {
|
protected void sendTargetUpdatedEvent(final JpaTarget target) {
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
||||||
@@ -172,7 +156,7 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
|
|
||||||
// document that the status has been retrieved
|
// document that the status has been retrieved
|
||||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
||||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "cancel obsolete action due to new update"));
|
RepositoryConstants.SERVER_MESSAGE_PREFIX + "cancel obsolete action due to new update"));
|
||||||
actionRepository.save(action);
|
actionRepository.save(action);
|
||||||
|
|
||||||
return action.getTarget().getId();
|
return action.getTarget().getId();
|
||||||
@@ -223,65 +207,70 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
* Sends the {@link CancelTargetAssignmentEvent} for a specific action to
|
* Sends the {@link CancelTargetAssignmentEvent} for a specific action to
|
||||||
* the eventPublisher.
|
* the eventPublisher.
|
||||||
*
|
*
|
||||||
* @param action
|
* @param action the action of the assignment
|
||||||
* the action of the assignment
|
|
||||||
*/
|
*/
|
||||||
protected void cancelAssignDistributionSetEvent(final Action action) {
|
protected void cancelAssignDistributionSetEvent(final Action action) {
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
||||||
new CancelTargetAssignmentEvent(action, eventPublisherHolder.getApplicationId())));
|
new CancelTargetAssignmentEvent(action, eventPublisherHolder.getApplicationId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAssignDistributionSetEvent(final List<Action> actions) {
|
protected boolean isMultiAssignmentsEnabled() {
|
||||||
if (CollectionUtils.isEmpty(actions)) {
|
return multiAssignmentsConfig.getAsBoolean();
|
||||||
return;
|
|
||||||
}
|
|
||||||
final String tenant = actions.get(0).getTenant();
|
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
|
||||||
.publishEvent(new CancelTargetAssignmentEvent(tenant,
|
|
||||||
actions, eventPublisherHolder.getApplicationId())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
protected boolean isConfirmationFlowEnabled() {
|
||||||
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
return confirmationFlowConfig.getAsBoolean();
|
||||||
final Optional<JpaTarget> optTarget = targets.stream()
|
|
||||||
.filter(t -> t.getControllerId().equals(targetWithActionType.getControllerId())).findFirst();
|
|
||||||
|
|
||||||
// create the action
|
|
||||||
return optTarget.map(target -> {
|
|
||||||
assertActionsPerTargetQuota(target, 1);
|
|
||||||
final JpaAction actionForTarget = new JpaAction();
|
|
||||||
actionForTarget.setActionType(targetWithActionType.getActionType());
|
|
||||||
actionForTarget.setForcedTime(targetWithActionType.getForceTime());
|
|
||||||
actionForTarget.setWeight(
|
|
||||||
targetWithActionType.getWeight() == null ?
|
|
||||||
repositoryProperties.getActionWeightIfAbsent() : targetWithActionType.getWeight());
|
|
||||||
actionForTarget.setActive(true);
|
|
||||||
actionForTarget.setTarget(target);
|
|
||||||
actionForTarget.setDistributionSet(set);
|
|
||||||
actionForTarget.setMaintenanceWindowSchedule(targetWithActionType.getMaintenanceSchedule());
|
|
||||||
actionForTarget.setMaintenanceWindowDuration(targetWithActionType.getMaintenanceWindowDuration());
|
|
||||||
actionForTarget.setMaintenanceWindowTimeZone(targetWithActionType.getMaintenanceWindowTimeZone());
|
|
||||||
actionForTarget.setInitiatedBy(initiatedBy);
|
|
||||||
return actionForTarget;
|
|
||||||
}).orElseGet(() -> {
|
|
||||||
log.warn("Cannot find target for targetWithActionType '{}'.", targetWithActionType.getControllerId());
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
/**
|
||||||
final JpaActionStatus actionStatus = new JpaActionStatus();
|
* Find targets to be considered for assignment.
|
||||||
actionStatus.setAction(action);
|
*
|
||||||
actionStatus.setOccurredAt(action.getCreatedAt());
|
* @param controllerIDs as provided by repository caller
|
||||||
|
* @param distributionSetId to assign
|
||||||
|
* @return list of targets up to {@link Constants#MAX_ENTRIES_IN_STATEMENT}
|
||||||
|
*/
|
||||||
|
abstract List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long distributionSetId);
|
||||||
|
|
||||||
if (StringUtils.hasText(actionMessage)) {
|
/**
|
||||||
actionStatus.addMessage(actionMessage);
|
* @param set
|
||||||
} else {
|
* @param targets
|
||||||
actionStatus.addMessage(getActionMessage(action));
|
*/
|
||||||
}
|
abstract void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets);
|
||||||
|
|
||||||
return actionStatus;
|
/**
|
||||||
}
|
* Update status and DS fields of given target.
|
||||||
|
*
|
||||||
|
* @param distributionSet to set
|
||||||
|
* @param targetIds to change
|
||||||
|
* @param currentUser for auditing
|
||||||
|
*/
|
||||||
|
abstract void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet distributionSet,
|
||||||
|
final List<List<Long>> targetIds, final String currentUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels actions that can be canceled (i.e.
|
||||||
|
* {@link DistributionSet#isRequiredMigrationStep() is <code>false</code>})
|
||||||
|
* as a result of the new assignment and returns all {@link Target}s where
|
||||||
|
* such actions existed.
|
||||||
|
*
|
||||||
|
* @param targetIds to cancel actions for
|
||||||
|
* @return {@link Set} of {@link Target#getId()}s
|
||||||
|
*/
|
||||||
|
abstract Set<Long> cancelActiveActions(List<List<Long>> targetIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels actions that can be canceled (i.e.
|
||||||
|
* {@link DistributionSet#isRequiredMigrationStep() is <code>false</code>})
|
||||||
|
* as a result of the new assignment and returns all {@link Target}s where
|
||||||
|
* such actions existed.
|
||||||
|
*
|
||||||
|
* @param targetIds to cancel actions for
|
||||||
|
*/
|
||||||
|
abstract void closeActiveActions(List<List<Long>> targetIds);
|
||||||
|
|
||||||
|
abstract void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult);
|
||||||
|
|
||||||
|
abstract void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults);
|
||||||
|
|
||||||
private static String getActionMessage(final Action action) {
|
private static String getActionMessage(final Action action) {
|
||||||
final RolloutGroup rolloutGroup = action.getRolloutGroup();
|
final RolloutGroup rolloutGroup = action.getRolloutGroup();
|
||||||
@@ -292,18 +281,20 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
return String.format("Assignment initiated by user '%s'", action.getInitiatedBy());
|
return String.format("Assignment initiated by user '%s'", action.getInitiatedBy());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void cancelAssignDistributionSetEvent(final List<Action> actions) {
|
||||||
|
if (CollectionUtils.isEmpty(actions)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String tenant = actions.get(0).getTenant();
|
||||||
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
||||||
|
.publishEvent(new CancelTargetAssignmentEvent(tenant,
|
||||||
|
actions, eventPublisherHolder.getApplicationId())));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertActionsPerTargetQuota(final Target target, final int requested) {
|
private void assertActionsPerTargetQuota(final Target target, final int requested) {
|
||||||
final int quota = quotaManagement.getMaxActionsPerTarget();
|
final int quota = quotaManagement.getMaxActionsPerTarget();
|
||||||
QuotaHelper.assertAssignmentQuota(target.getId(), requested, quota, Action.class, Target.class,
|
QuotaHelper.assertAssignmentQuota(target.getId(), requested, quota, Action.class, Target.class,
|
||||||
actionRepository::countByTargetId);
|
actionRepository::countByTargetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isMultiAssignmentsEnabled() {
|
|
||||||
return multiAssignmentsConfig.getAsBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isConfirmationFlowEnabled() {
|
|
||||||
return confirmationFlowConfig.getAsBoolean();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.management;
|
package org.eclipse.hawkbit.repository.jpa.management;
|
||||||
|
|
||||||
|
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
|
||||||
|
import static org.eclipse.hawkbit.repository.model.Action.Status.ERROR;
|
||||||
|
import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||||
@@ -27,15 +36,6 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
|
|
||||||
import static org.eclipse.hawkbit.repository.model.Action.Status.ERROR;
|
|
||||||
import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements utility methods for managing {@link Action}s
|
* Implements utility methods for managing {@link Action}s
|
||||||
*/
|
*/
|
||||||
@@ -56,6 +56,54 @@ public class JpaActionManagement {
|
|||||||
this.repositoryProperties = repositoryProperties;
|
this.repositoryProperties = repositoryProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getWeightConsideringDefault(final Action action) {
|
||||||
|
return action.getWeight().orElse(repositoryProperties.getActionWeightIfAbsent());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean isDownloadOnly(final JpaAction action) {
|
||||||
|
return DOWNLOAD_ONLY == action.getActionType();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<JpaAction> findActiveActionsHavingStatus(final String controllerId, final Action.Status status) {
|
||||||
|
return actionRepository.findAll(
|
||||||
|
ActionSpecifications.byTargetControllerIdAndIsActiveAndStatus(controllerId, status));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Action addActionStatus(final JpaActionStatusCreate statusCreate) {
|
||||||
|
final Long actionId = statusCreate.getActionId();
|
||||||
|
final JpaActionStatus actionStatus = statusCreate.build();
|
||||||
|
final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId);
|
||||||
|
|
||||||
|
if (isUpdatingActionStatusAllowed(action, actionStatus)) {
|
||||||
|
return handleAddUpdateActionStatus(actionStatus, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Update of actionStatus {} for action {} not possible since action not active anymore.",
|
||||||
|
actionStatus.getStatus(), action.getId());
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) {
|
||||||
|
return actionRepository.findById(actionId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onActionStatusUpdate(final Action.Status updatedActionStatus, final JpaAction action) {
|
||||||
|
// can be overwritten to intercept the persistence of the action status
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertActionStatusQuota(final JpaActionStatus newActionStatus, final JpaAction action) {
|
||||||
|
if (isIntermediateStatus(newActionStatus)) {// check for quota only for intermediate statuses
|
||||||
|
QuotaHelper.assertAssignmentQuota(action.getId(), 1, quotaManagement.getMaxStatusEntriesPerAction(),
|
||||||
|
ActionStatus.class, Action.class, actionStatusRepository::countByActionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertActionStatusMessageQuota(final JpaActionStatus actionStatus) {
|
||||||
|
QuotaHelper.assertAssignmentQuota(actionStatus.getId(), actionStatus.getMessages().size(),
|
||||||
|
quotaManagement.getMaxMessagesPerActionStatus(), "Message", ActionStatus.class.getSimpleName(), null);
|
||||||
|
}
|
||||||
|
|
||||||
List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId,
|
List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId,
|
||||||
final int maxActionCount) {
|
final int maxActionCount) {
|
||||||
final List<Action> actions = new ArrayList<>();
|
final List<Action> actions = new ArrayList<>();
|
||||||
@@ -84,23 +132,8 @@ public class JpaActionManagement {
|
|||||||
return actions.stream().sorted(actionImportance).limit(maxActionCount).collect(Collectors.toList());
|
return actions.stream().sorted(actionImportance).limit(maxActionCount).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<JpaAction> findActiveActionsHavingStatus(final String controllerId, final Action.Status status) {
|
private static boolean isIntermediateStatus(final JpaActionStatus actionStatus) {
|
||||||
return actionRepository.findAll(
|
return FINISHED != actionStatus.getStatus() && ERROR != actionStatus.getStatus();
|
||||||
ActionSpecifications.byTargetControllerIdAndIsActiveAndStatus(controllerId, status));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Action addActionStatus(final JpaActionStatusCreate statusCreate) {
|
|
||||||
final Long actionId = statusCreate.getActionId();
|
|
||||||
final JpaActionStatus actionStatus = statusCreate.build();
|
|
||||||
final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId);
|
|
||||||
|
|
||||||
if (isUpdatingActionStatusAllowed(action, actionStatus)) {
|
|
||||||
return handleAddUpdateActionStatus(actionStatus, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("Update of actionStatus {} for action {} not possible since action not active anymore.",
|
|
||||||
actionStatus.getStatus(), action.getId());
|
|
||||||
return action;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,25 +150,12 @@ public class JpaActionManagement {
|
|||||||
final boolean isAllowedByRepositoryConfiguration = intermediateStatus && !repositoryProperties.isRejectActionStatusForClosedAction();
|
final boolean isAllowedByRepositoryConfiguration = intermediateStatus && !repositoryProperties.isRejectActionStatusForClosedAction();
|
||||||
|
|
||||||
//in case of download_only action Status#DOWNLOADED is treated as 'final' already, so we accept one final status from device in case it sends
|
//in case of download_only action Status#DOWNLOADED is treated as 'final' already, so we accept one final status from device in case it sends
|
||||||
final boolean isAllowedForDownloadOnlyActions = isDownloadOnly(action) && action.getStatus() == Action.Status.DOWNLOADED && !intermediateStatus;
|
final boolean isAllowedForDownloadOnlyActions = isDownloadOnly(
|
||||||
|
action) && action.getStatus() == Action.Status.DOWNLOADED && !intermediateStatus;
|
||||||
|
|
||||||
return action.isActive() || isAllowedByRepositoryConfiguration || isAllowedForDownloadOnlyActions;
|
return action.isActive() || isAllowedByRepositoryConfiguration || isAllowedForDownloadOnlyActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWeightConsideringDefault(final Action action) {
|
|
||||||
return action.getWeight().orElse(repositoryProperties.getActionWeightIfAbsent());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) {
|
|
||||||
return actionRepository.findById(actionId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean isDownloadOnly(final JpaAction action) {
|
|
||||||
return DOWNLOAD_ONLY == action.getActionType();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}.
|
* Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}.
|
||||||
*/
|
*/
|
||||||
@@ -152,24 +172,4 @@ public class JpaActionManagement {
|
|||||||
action.setLastActionStatusCode(actionStatus.getCode().orElse(null));
|
action.setLastActionStatusCode(actionStatus.getCode().orElse(null));
|
||||||
return actionRepository.save(action);
|
return actionRepository.save(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onActionStatusUpdate(final Action.Status updatedActionStatus, final JpaAction action){
|
|
||||||
// can be overwritten to intercept the persistence of the action status
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void assertActionStatusQuota(final JpaActionStatus newActionStatus, final JpaAction action) {
|
|
||||||
if (isIntermediateStatus(newActionStatus)) {// check for quota only for intermediate statuses
|
|
||||||
QuotaHelper.assertAssignmentQuota(action.getId(), 1, quotaManagement.getMaxStatusEntriesPerAction(),
|
|
||||||
ActionStatus.class, Action.class, actionStatusRepository::countByActionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void assertActionStatusMessageQuota(final JpaActionStatus actionStatus) {
|
|
||||||
QuotaHelper.assertAssignmentQuota(actionStatus.getId(), actionStatus.getMessages().size(),
|
|
||||||
quotaManagement.getMaxMessagesPerActionStatus(), "Message", ActionStatus.class.getSimpleName(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isIntermediateStatus(final JpaActionStatus actionStatus) {
|
|
||||||
return FINISHED != actionStatus.getStatus() && ERROR != actionStatus.getStatus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||||
import org.eclipse.hawkbit.artifact.repository.ArtifactStoreException;
|
import org.eclipse.hawkbit.artifact.repository.ArtifactStoreException;
|
||||||
@@ -58,8 +60,6 @@ import org.springframework.transaction.support.TransactionSynchronization;
|
|||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA based {@link ArtifactManagement} implementation.
|
* JPA based {@link ArtifactManagement} implementation.
|
||||||
*/
|
*/
|
||||||
@@ -92,6 +92,11 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
this.tenantAware = tenantAware;
|
this.tenantAware = tenantAware;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long count() {
|
||||||
|
return localArtifactRepository.count();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -127,90 +132,6 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload, final boolean isSmEncrypted) {
|
|
||||||
final String tenant = tenantAware.getCurrentTenant();
|
|
||||||
final long smId = artifactUpload.getModuleId();
|
|
||||||
final InputStream stream = artifactUpload.getInputStream();
|
|
||||||
final String fileName = artifactUpload.getFilename();
|
|
||||||
final String contentType = artifactUpload.getContentType();
|
|
||||||
final String providedSha1 = artifactUpload.getProvidedSha1Sum();
|
|
||||||
final String providedMd5 = artifactUpload.getProvidedMd5Sum();
|
|
||||||
final String providedSha256 = artifactUpload.getProvidedSha256Sum();
|
|
||||||
|
|
||||||
try (final InputStream wrappedStream = wrapInQuotaStream(
|
|
||||||
isSmEncrypted ? wrapInEncryptionStream(smId, stream) : stream)) {
|
|
||||||
return artifactRepository.store(tenant, wrappedStream, fileName, contentType,
|
|
||||||
new DbArtifactHash(providedSha1, providedMd5, providedSha256));
|
|
||||||
} catch (final ArtifactStoreException | IOException e) {
|
|
||||||
throw new ArtifactUploadFailedException(e);
|
|
||||||
} catch (final HashNotMatchException e) {
|
|
||||||
if (e.getHashFunction().equals(HashNotMatchException.SHA1)) {
|
|
||||||
throw new InvalidSHA1HashException(e.getMessage(), e);
|
|
||||||
} else if (e.getHashFunction().equals(HashNotMatchException.SHA256)) {
|
|
||||||
throw new InvalidSHA256HashException(e.getMessage(), e);
|
|
||||||
} else {
|
|
||||||
throw new InvalidMD5HashException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputStream wrapInEncryptionStream(final long smId, final InputStream stream) {
|
|
||||||
return ArtifactEncryptionService.getInstance().encryptSoftwareModuleArtifact(smId, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertArtifactQuota(final long moduleId, final int requested) {
|
|
||||||
QuotaHelper.assertAssignmentQuota(
|
|
||||||
moduleId, requested, quotaManagement.getMaxArtifactsPerSoftwareModule(),
|
|
||||||
Artifact.class, SoftwareModule.class,
|
|
||||||
// get all artifacts without user context
|
|
||||||
softwareModuleId -> localArtifactRepository
|
|
||||||
.count(null, ArtifactSpecifications.bySoftwareModuleId(softwareModuleId)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputStream wrapInQuotaStream(final InputStream in) {
|
|
||||||
final long maxArtifactSize = quotaManagement.getMaxArtifactSize();
|
|
||||||
|
|
||||||
final long currentlyUsed = localArtifactRepository.sumOfNonDeletedArtifactSize().orElse(0L);
|
|
||||||
final long maxArtifactSizeTotal = quotaManagement.getMaxArtifactStorage();
|
|
||||||
|
|
||||||
return new FileSizeAndStorageQuotaCheckingInputStream(in, maxArtifactSize,
|
|
||||||
maxArtifactSizeTotal - currentlyUsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Garbage collects artifact binaries if only referenced by given
|
|
||||||
* {@link SoftwareModule#getId()} or {@link SoftwareModule}'s that are
|
|
||||||
* marked as deleted.
|
|
||||||
* <p/>
|
|
||||||
* Software module related UPDATE permission shall be checked by the callers!
|
|
||||||
*
|
|
||||||
* @param sha1Hash no longer needed
|
|
||||||
* @param softwareModuleId the garbage collection call is made for
|
|
||||||
*/
|
|
||||||
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
|
||||||
void clearArtifactBinary(final String sha1Hash) {
|
|
||||||
// countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse will skip ACM checks and
|
|
||||||
// will return total count as it should be
|
|
||||||
final long count = localArtifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(
|
|
||||||
sha1Hash,
|
|
||||||
tenantAware.getCurrentTenant());
|
|
||||||
if (count <= 1) { // 1 artifact is the one being deleted!
|
|
||||||
// removes the real artifact ONLY AFTER the delete of artifact or software module
|
|
||||||
// in local history has passed successfully (caller has permission and no errors)
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
|
||||||
@Override
|
|
||||||
public void afterCommit() {
|
|
||||||
try {
|
|
||||||
log.debug("deleting artifact from repository {}", sha1Hash);
|
|
||||||
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash);
|
|
||||||
} catch (final ArtifactStoreException e) {
|
|
||||||
throw new ArtifactDeleteFailedException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} // else there are still other artifacts that need the binary
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -222,7 +143,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
// clearArtifactBinary checks (unconditionally) software module UPDATE access
|
// clearArtifactBinary checks (unconditionally) software module UPDATE access
|
||||||
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
||||||
accessController.assertOperationAllowed(AccessController.Operation.UPDATE,
|
accessController.assertOperationAllowed(AccessController.Operation.UPDATE,
|
||||||
(JpaSoftwareModule) toDelete.getSoftwareModule()));
|
(JpaSoftwareModule) toDelete.getSoftwareModule()));
|
||||||
((JpaSoftwareModule) toDelete.getSoftwareModule()).removeArtifact(toDelete);
|
((JpaSoftwareModule) toDelete.getSoftwareModule()).removeArtifact(toDelete);
|
||||||
softwareModuleRepository.save((JpaSoftwareModule) toDelete.getSoftwareModule());
|
softwareModuleRepository.save((JpaSoftwareModule) toDelete.getSoftwareModule());
|
||||||
|
|
||||||
@@ -268,11 +189,6 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
return localArtifactRepository.count(ArtifactSpecifications.bySoftwareModuleId(softwareModuleId));
|
return localArtifactRepository.count(ArtifactSpecifications.bySoftwareModuleId(softwareModuleId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count() {
|
|
||||||
return localArtifactRepository.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<DbArtifact> loadArtifactBinary(final String sha1Hash, final long softwareModuleId,
|
public Optional<DbArtifact> loadArtifactBinary(final String sha1Hash, final long softwareModuleId,
|
||||||
final boolean isEncrypted) {
|
final boolean isEncrypted) {
|
||||||
@@ -293,6 +209,91 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Garbage collects artifact binaries if only referenced by given
|
||||||
|
* {@link SoftwareModule#getId()} or {@link SoftwareModule}'s that are
|
||||||
|
* marked as deleted.
|
||||||
|
* <p/>
|
||||||
|
* Software module related UPDATE permission shall be checked by the callers!
|
||||||
|
*
|
||||||
|
* @param sha1Hash no longer needed
|
||||||
|
* @param softwareModuleId the garbage collection call is made for
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||||
|
void clearArtifactBinary(final String sha1Hash) {
|
||||||
|
// countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse will skip ACM checks and
|
||||||
|
// will return total count as it should be
|
||||||
|
final long count = localArtifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(
|
||||||
|
sha1Hash,
|
||||||
|
tenantAware.getCurrentTenant());
|
||||||
|
if (count <= 1) { // 1 artifact is the one being deleted!
|
||||||
|
// removes the real artifact ONLY AFTER the delete of artifact or software module
|
||||||
|
// in local history has passed successfully (caller has permission and no errors)
|
||||||
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCommit() {
|
||||||
|
try {
|
||||||
|
log.debug("deleting artifact from repository {}", sha1Hash);
|
||||||
|
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash);
|
||||||
|
} catch (final ArtifactStoreException e) {
|
||||||
|
throw new ArtifactDeleteFailedException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} // else there are still other artifacts that need the binary
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload, final boolean isSmEncrypted) {
|
||||||
|
final String tenant = tenantAware.getCurrentTenant();
|
||||||
|
final long smId = artifactUpload.getModuleId();
|
||||||
|
final InputStream stream = artifactUpload.getInputStream();
|
||||||
|
final String fileName = artifactUpload.getFilename();
|
||||||
|
final String contentType = artifactUpload.getContentType();
|
||||||
|
final String providedSha1 = artifactUpload.getProvidedSha1Sum();
|
||||||
|
final String providedMd5 = artifactUpload.getProvidedMd5Sum();
|
||||||
|
final String providedSha256 = artifactUpload.getProvidedSha256Sum();
|
||||||
|
|
||||||
|
try (final InputStream wrappedStream = wrapInQuotaStream(
|
||||||
|
isSmEncrypted ? wrapInEncryptionStream(smId, stream) : stream)) {
|
||||||
|
return artifactRepository.store(tenant, wrappedStream, fileName, contentType,
|
||||||
|
new DbArtifactHash(providedSha1, providedMd5, providedSha256));
|
||||||
|
} catch (final ArtifactStoreException | IOException e) {
|
||||||
|
throw new ArtifactUploadFailedException(e);
|
||||||
|
} catch (final HashNotMatchException e) {
|
||||||
|
if (e.getHashFunction().equals(HashNotMatchException.SHA1)) {
|
||||||
|
throw new InvalidSHA1HashException(e.getMessage(), e);
|
||||||
|
} else if (e.getHashFunction().equals(HashNotMatchException.SHA256)) {
|
||||||
|
throw new InvalidSHA256HashException(e.getMessage(), e);
|
||||||
|
} else {
|
||||||
|
throw new InvalidMD5HashException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream wrapInEncryptionStream(final long smId, final InputStream stream) {
|
||||||
|
return ArtifactEncryptionService.getInstance().encryptSoftwareModuleArtifact(smId, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertArtifactQuota(final long moduleId, final int requested) {
|
||||||
|
QuotaHelper.assertAssignmentQuota(
|
||||||
|
moduleId, requested, quotaManagement.getMaxArtifactsPerSoftwareModule(),
|
||||||
|
Artifact.class, SoftwareModule.class,
|
||||||
|
// get all artifacts without user context
|
||||||
|
softwareModuleId -> localArtifactRepository
|
||||||
|
.count(null, ArtifactSpecifications.bySoftwareModuleId(softwareModuleId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream wrapInQuotaStream(final InputStream in) {
|
||||||
|
final long maxArtifactSize = quotaManagement.getMaxArtifactSize();
|
||||||
|
|
||||||
|
final long currentlyUsed = localArtifactRepository.sumOfNonDeletedArtifactSize().orElse(0L);
|
||||||
|
final long maxArtifactSizeTotal = quotaManagement.getMaxArtifactStorage();
|
||||||
|
|
||||||
|
return new FileSizeAndStorageQuotaCheckingInputStream(in, maxArtifactSize,
|
||||||
|
maxArtifactSizeTotal - currentlyUsed);
|
||||||
|
}
|
||||||
|
|
||||||
private DbArtifact wrapInEncryptionAwareDbArtifact(final long softwareModuleId, final DbArtifact dbArtifact) {
|
private DbArtifact wrapInEncryptionAwareDbArtifact(final long softwareModuleId, final DbArtifact dbArtifact) {
|
||||||
if (dbArtifact == null) {
|
if (dbArtifact == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
|||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public JpaConfirmationManagement(final TargetRepository targetRepository,
|
public JpaConfirmationManagement(final TargetRepository targetRepository,
|
||||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||||
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
||||||
final EntityFactory entityFactory) {
|
final EntityFactory entityFactory) {
|
||||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||||
this.targetRepository = targetRepository;
|
this.targetRepository = targetRepository;
|
||||||
this.entityFactory = entityFactory;
|
this.entityFactory = entityFactory;
|
||||||
@@ -96,7 +96,7 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
|||||||
final AutoConfirmationStatus autoConfStatus = updatedTarget.getAutoConfirmationStatus();
|
final AutoConfirmationStatus autoConfStatus = updatedTarget.getAutoConfirmationStatus();
|
||||||
if (autoConfStatus == null) {
|
if (autoConfStatus == null) {
|
||||||
final String message = String.format("Persisted auto confirmation status is null. "
|
final String message = String.format("Persisted auto confirmation status is null. "
|
||||||
+ "Cannot proceed with giving confirmations for active actions for device %s with initiator %s.",
|
+ "Cannot proceed with giving confirmations for active actions for device %s with initiator %s.",
|
||||||
controllerId, initiator);
|
controllerId, initiator);
|
||||||
log.error("message");
|
log.error("message");
|
||||||
throw new IllegalStateException(message);
|
throw new IllegalStateException(message);
|
||||||
@@ -159,17 +159,20 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
|||||||
return addActionStatus((JpaActionStatusCreate) statusCreate);
|
return addActionStatus((JpaActionStatusCreate) statusCreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActionStatusCreate createConfirmationActionStatus(final long actionId, final Integer code,
|
@Override
|
||||||
final Collection<String> messages) {
|
@Transactional
|
||||||
final ActionStatusCreate statusCreate = entityFactory.actionStatus().create(actionId);
|
public void deactivateAutoConfirmation(String controllerId) {
|
||||||
if (!CollectionUtils.isEmpty(messages)) {
|
log.debug("Deactivate auto confirmation for controllerId '{}'", controllerId);
|
||||||
statusCreate.messages(messages);
|
final JpaTarget target = getTargetByControllerIdAndThrowIfNotFound(controllerId);
|
||||||
|
target.setAutoConfirmationStatus(null);
|
||||||
|
targetRepository.save(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActionStatusUpdate(final Status updatedActionStatus, final JpaAction action) {
|
||||||
|
if (updatedActionStatus == Status.RUNNING && action.isActive()) {
|
||||||
|
action.setStatus(Status.RUNNING);
|
||||||
}
|
}
|
||||||
if (code != null) {
|
|
||||||
statusCreate.code(code);
|
|
||||||
statusCreate.message(String.format(CONFIRMATION_CODE_MSG_PREFIX, code));
|
|
||||||
}
|
|
||||||
return statusCreate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertActionCanAcceptFeedback(final Action action) {
|
private static void assertActionCanAcceptFeedback(final Action action) {
|
||||||
@@ -188,6 +191,19 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ActionStatusCreate createConfirmationActionStatus(final long actionId, final Integer code,
|
||||||
|
final Collection<String> messages) {
|
||||||
|
final ActionStatusCreate statusCreate = entityFactory.actionStatus().create(actionId);
|
||||||
|
if (!CollectionUtils.isEmpty(messages)) {
|
||||||
|
statusCreate.messages(messages);
|
||||||
|
}
|
||||||
|
if (code != null) {
|
||||||
|
statusCreate.code(code);
|
||||||
|
statusCreate.message(String.format(CONFIRMATION_CODE_MSG_PREFIX, code));
|
||||||
|
}
|
||||||
|
return statusCreate;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Action> giveConfirmationForActiveActions(final AutoConfirmationStatus autoConfirmationStatus) {
|
private List<Action> giveConfirmationForActiveActions(final AutoConfirmationStatus autoConfirmationStatus) {
|
||||||
final Target target = autoConfirmationStatus.getTarget();
|
final Target target = autoConfirmationStatus.getTarget();
|
||||||
return findActiveActionsHavingStatus(target.getControllerId(), Status.WAIT_FOR_CONFIRMATION).stream()
|
return findActiveActionsHavingStatus(target.getControllerId(), Status.WAIT_FOR_CONFIRMATION).stream()
|
||||||
@@ -218,24 +234,8 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
|||||||
return actionRepository.save(action);
|
return actionRepository.save(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void deactivateAutoConfirmation(String controllerId) {
|
|
||||||
log.debug("Deactivate auto confirmation for controllerId '{}'", controllerId);
|
|
||||||
final JpaTarget target = getTargetByControllerIdAndThrowIfNotFound(controllerId);
|
|
||||||
target.setAutoConfirmationStatus(null);
|
|
||||||
targetRepository.save(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
private JpaTarget getTargetByControllerIdAndThrowIfNotFound(final String controllerId) {
|
private JpaTarget getTargetByControllerIdAndThrowIfNotFound(final String controllerId) {
|
||||||
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
|
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActionStatusUpdate(final Status updatedActionStatus, final JpaAction action) {
|
|
||||||
if (updatedActionStatus == Status.RUNNING && action.isActive()) {
|
|
||||||
action.setStatus(Status.RUNNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -127,16 +127,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
+ ACTION_PAGE_LIMIT;
|
+ ACTION_PAGE_LIMIT;
|
||||||
|
|
||||||
private static final EnumMap<Database, String> QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED;
|
private static final EnumMap<Database, String> QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED;
|
||||||
|
|
||||||
static {
|
|
||||||
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED = new EnumMap<>(Database.class);
|
|
||||||
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.put(Database.SQL_SERVER, "DELETE TOP (" + ACTION_PAGE_LIMIT
|
|
||||||
+ ") FROM sp_action WHERE tenant=#tenant AND status IN (%s) AND last_modified_at<#last_modified_at ");
|
|
||||||
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.put(Database.POSTGRESQL,
|
|
||||||
"DELETE FROM sp_action WHERE id IN (SELECT id FROM sp_action WHERE tenant=#tenant AND status IN (%s) AND last_modified_at<#last_modified_at LIMIT "
|
|
||||||
+ ACTION_PAGE_LIMIT + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
private final EntityManager entityManager;
|
private final EntityManager entityManager;
|
||||||
private final DistributionSetManagement distributionSetManagement;
|
private final DistributionSetManagement distributionSetManagement;
|
||||||
private final TargetRepository targetRepository;
|
private final TargetRepository targetRepository;
|
||||||
@@ -152,6 +142,15 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
private final Database database;
|
private final Database database;
|
||||||
private final RetryTemplate retryTemplate;
|
private final RetryTemplate retryTemplate;
|
||||||
|
|
||||||
|
static {
|
||||||
|
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED = new EnumMap<>(Database.class);
|
||||||
|
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.put(Database.SQL_SERVER, "DELETE TOP (" + ACTION_PAGE_LIMIT
|
||||||
|
+ ") FROM sp_action WHERE tenant=#tenant AND status IN (%s) AND last_modified_at<#last_modified_at ");
|
||||||
|
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.put(Database.POSTGRESQL,
|
||||||
|
"DELETE FROM sp_action WHERE id IN (SELECT id FROM sp_action WHERE tenant=#tenant AND status IN (%s) AND last_modified_at<#last_modified_at LIMIT "
|
||||||
|
+ ACTION_PAGE_LIMIT + ")");
|
||||||
|
}
|
||||||
|
|
||||||
public JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository,
|
public JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository,
|
||||||
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||||
@@ -183,9 +182,18 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||||
public List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(
|
public List<DistributionSetAssignmentResult> assignDistributionSets(
|
||||||
final Collection<Entry<String, Long>> assignments) {
|
final List<DeploymentRequest> deploymentRequests) {
|
||||||
return offlineAssignedDistributionSets(assignments,tenantAware.getCurrentUsername());
|
return assignDistributionSets(tenantAware.getCurrentUsername(), deploymentRequests, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||||
|
public List<DistributionSetAssignmentResult> assignDistributionSets(final String initiatedBy,
|
||||||
|
final List<DeploymentRequest> deploymentRequests, final String actionMessage) {
|
||||||
|
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
||||||
|
.validate(deploymentRequests);
|
||||||
|
return assignDistributionSets(initiatedBy, deploymentRequests, actionMessage, onlineDsAssignmentStrategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -205,18 +213,422 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||||
public List<DistributionSetAssignmentResult> assignDistributionSets(
|
public List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(
|
||||||
final List<DeploymentRequest> deploymentRequests) {
|
final Collection<Entry<String, Long>> assignments) {
|
||||||
return assignDistributionSets(tenantAware.getCurrentUsername(), deploymentRequests, null);
|
return offlineAssignedDistributionSets(assignments, tenantAware.getCurrentUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||||
public List<DistributionSetAssignmentResult> assignDistributionSets(final String initiatedBy,
|
@Retryable(include = {
|
||||||
final List<DeploymentRequest> deploymentRequests, final String actionMessage) {
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
public Action cancelAction(final long actionId) {
|
||||||
.validate(deploymentRequests);
|
log.debug("cancelAction({})", actionId);
|
||||||
return assignDistributionSets(initiatedBy, deploymentRequests, actionMessage, onlineDsAssignmentStrategy);
|
|
||||||
|
final JpaAction action = actionRepository.findById(actionId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||||
|
|
||||||
|
if (action.isCancelingOrCanceled()) {
|
||||||
|
throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled");
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTargetUpdateAllowed(action);
|
||||||
|
|
||||||
|
if (action.isActive()) {
|
||||||
|
log.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING);
|
||||||
|
action.setStatus(Status.CANCELING);
|
||||||
|
|
||||||
|
// document that the status has been retrieved
|
||||||
|
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
||||||
|
RepositoryConstants.SERVER_MESSAGE_PREFIX + "manual cancelation requested"));
|
||||||
|
final Action saveAction = actionRepository.save(action);
|
||||||
|
|
||||||
|
onlineDsAssignmentStrategy.cancelAssignment(action);
|
||||||
|
|
||||||
|
return saveAction;
|
||||||
|
} else {
|
||||||
|
throw new CancelActionNotAllowedException(action.getId() + " is not active and cannot be canceled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countActionsByTarget(final String rsqlParam, final String controllerId) {
|
||||||
|
assertTargetReadAllowed(controllerId);
|
||||||
|
|
||||||
|
final List<Specification<JpaAction>> specList = Arrays.asList(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database),
|
||||||
|
ActionSpecifications.byTargetControllerId(controllerId));
|
||||||
|
|
||||||
|
return JpaManagementHelper.countBySpec(actionRepository, specList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countActionsAll() {
|
||||||
|
return actionRepository.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countActions(final String rsqlParam) {
|
||||||
|
final List<Specification<JpaAction>> specList = List.of(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database));
|
||||||
|
return JpaManagementHelper.countBySpec(actionRepository, specList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countActionsByTarget(final String controllerId) {
|
||||||
|
assertTargetReadAllowed(controllerId);
|
||||||
|
return actionRepository.countByTargetControllerId(controllerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Action> findAction(final long actionId) {
|
||||||
|
return actionRepository.findById(actionId)
|
||||||
|
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())))
|
||||||
|
.map(JpaAction.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<Action> findActionsAll(final Pageable pageable) {
|
||||||
|
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, pageable, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<Action> findActions(final String rsqlParam, final Pageable pageable) {
|
||||||
|
final List<Specification<JpaAction>> specList = List.of(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database));
|
||||||
|
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, pageable, specList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Action> findActionsByTarget(final String rsqlParam, final String controllerId,
|
||||||
|
final Pageable pageable) {
|
||||||
|
assertTargetReadAllowed(controllerId);
|
||||||
|
|
||||||
|
final List<Specification<JpaAction>> specList = Arrays.asList(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database),
|
||||||
|
ActionSpecifications.byTargetControllerId(controllerId));
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(actionRepository, pageable, specList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<Action> findActionsByTarget(final String controllerId, final Pageable pageable) {
|
||||||
|
assertTargetReadAllowed(controllerId);
|
||||||
|
return actionRepository.findAll(ActionSpecifications.byTargetControllerId(controllerId), pageable)
|
||||||
|
.map(Action.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<ActionStatus> findActionStatusByAction(final Pageable pageReq, final long actionId) {
|
||||||
|
assertActionExistsAndAccessible(actionId);
|
||||||
|
|
||||||
|
return actionStatusRepository.findByActionId(pageReq, actionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countActionStatusByAction(final long actionId) {
|
||||||
|
assertActionExistsAndAccessible(actionId);
|
||||||
|
|
||||||
|
return actionStatusRepository.countByActionId(actionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// action is already got and there are checked read permissions - do not check
|
||||||
|
// permissions
|
||||||
|
// and UI which is to be removed
|
||||||
|
@Override
|
||||||
|
public Page<String> findMessagesByActionStatusId(final Pageable pageable, final long actionStatusId) {
|
||||||
|
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||||
|
|
||||||
|
final CriteriaQuery<String> msgQuery = cb.createQuery(String.class);
|
||||||
|
final Root<JpaActionStatus> as = msgQuery.from(JpaActionStatus.class);
|
||||||
|
final ListJoin<JpaActionStatus, String> join = as.joinList("messages", JoinType.LEFT);
|
||||||
|
final CriteriaQuery<String> selMsgQuery = msgQuery.select(join);
|
||||||
|
selMsgQuery.where(cb.equal(as.get(JpaActionStatus_.id), actionStatusId));
|
||||||
|
|
||||||
|
final List<String> result = new ArrayList<>(entityManager.createQuery(selMsgQuery)
|
||||||
|
.setFirstResult((int) pageable.getOffset()).setMaxResults(pageable.getPageSize()).getResultList());
|
||||||
|
|
||||||
|
return new PageImpl<>(result, pageable, result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Action> findActionWithDetails(final long actionId) {
|
||||||
|
return actionRepository.findWithDetailsById(actionId)
|
||||||
|
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
||||||
|
assertTargetReadAllowed(controllerId);
|
||||||
|
return actionRepository
|
||||||
|
.findAll(ActionSpecifications.byTargetControllerIdAndActive(controllerId, true), pageable)
|
||||||
|
.map(Action.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Action> findInActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
||||||
|
assertTargetReadAllowed(controllerId);
|
||||||
|
return actionRepository
|
||||||
|
.findAll(ActionSpecifications.byTargetControllerIdAndActive(controllerId, false), pageable)
|
||||||
|
.map(Action.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Action> findActiveActionsWithHighestWeight(final String controllerId, final int maxActionCount) {
|
||||||
|
assertTargetReadAllowed(controllerId);
|
||||||
|
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public Action forceQuitAction(final long actionId) {
|
||||||
|
final JpaAction action = actionRepository.findById(actionId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||||
|
|
||||||
|
if (!action.isCancelingOrCanceled()) {
|
||||||
|
throw new ForceQuitActionNotAllowedException(
|
||||||
|
action.getId() + " is not canceled yet and cannot be force quit");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!action.isActive()) {
|
||||||
|
throw new ForceQuitActionNotAllowedException(action.getId() + " is not active and cannot be force quit");
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTargetUpdateAllowed(action);
|
||||||
|
|
||||||
|
log.warn("action ({}) was still active and has been force quite.", action);
|
||||||
|
|
||||||
|
// document that the status has been retrieved
|
||||||
|
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELED, System.currentTimeMillis(),
|
||||||
|
RepositoryConstants.SERVER_MESSAGE_PREFIX + "A force quit has been performed."));
|
||||||
|
|
||||||
|
DeploymentHelper.successCancellation(action, actionRepository, targetRepository);
|
||||||
|
|
||||||
|
return actionRepository.save(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public Action forceTargetAction(final long actionId) {
|
||||||
|
final JpaAction action = actionRepository.findById(actionId).map(this::assertTargetUpdateAllowed)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||||
|
|
||||||
|
if (!action.isForcedOrTimeForced()) {
|
||||||
|
action.setActionType(ActionType.FORCED);
|
||||||
|
return actionRepository.save(action);
|
||||||
|
}
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void cancelInactiveScheduledActionsForTargets(final List<Long> targetIds) {
|
||||||
|
if (!isMultiAssignmentsEnabled()) {
|
||||||
|
targetRepository.getAccessController().ifPresent(v -> {
|
||||||
|
if (targetRepository.count(AccessController.Operation.UPDATE,
|
||||||
|
TargetSpecifications.hasIdIn(targetIds)) != targetIds.size()) {
|
||||||
|
throw new EntityNotFoundException(Target.class, targetIds);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
actionRepository.switchStatus(Status.CANCELED, targetIds, false, Status.SCHEDULED);
|
||||||
|
} else {
|
||||||
|
log.debug("The Multi Assignments feature is enabled: No need to cancel inactive scheduled actions.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startScheduledActionsByRolloutGroupParent(final long rolloutId, final long distributionSetId,
|
||||||
|
final Long rolloutGroupParentId) {
|
||||||
|
while (DeploymentHelper.runInNewTransaction(
|
||||||
|
txManager,
|
||||||
|
"startScheduledActions-" + rolloutId,
|
||||||
|
status -> {
|
||||||
|
final PageRequest pageRequest = PageRequest.of(0, ACTION_PAGE_LIMIT);
|
||||||
|
final Page<Action> groupScheduledActions;
|
||||||
|
if (rolloutGroupParentId == null) {
|
||||||
|
groupScheduledActions = actionRepository.findByRolloutIdAndRolloutGroupParentIsNullAndStatus(pageRequest, rolloutId,
|
||||||
|
Action.Status.SCHEDULED);
|
||||||
|
} else {
|
||||||
|
groupScheduledActions = actionRepository.findByRolloutIdAndRolloutGroupParentIdAndStatus(pageRequest, rolloutId,
|
||||||
|
rolloutGroupParentId, Action.Status.SCHEDULED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupScheduledActions.getContent().isEmpty()) {
|
||||||
|
return 0L;
|
||||||
|
} else {
|
||||||
|
// self invocation won't check @PreAuthorize but it is already checked for the method
|
||||||
|
startScheduledActions(groupScheduledActions.getContent());
|
||||||
|
return groupScheduledActions.getTotalElements();
|
||||||
|
}
|
||||||
|
}) > 0) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startScheduledActions(final List<Action> rolloutGroupActions) {
|
||||||
|
// Close actions already assigned and collect pending assignments
|
||||||
|
final List<JpaAction> pendingTargetAssignments = rolloutGroupActions.stream()
|
||||||
|
.map(JpaAction.class::cast)
|
||||||
|
.map(this::closeActionIfSetWasAlreadyAssigned)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
if (pendingTargetAssignments.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// check if old actions needs to be canceled first
|
||||||
|
final List<Action> newTargetAssignments = startScheduledActionsAndHandleOpenCancellationFirst(pendingTargetAssignments);
|
||||||
|
if (!newTargetAssignments.isEmpty()) {
|
||||||
|
onlineDsAssignmentStrategy.sendDeploymentEvents(newTargetAssignments.get(0).getDistributionSet().getId(), newTargetAssignments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
|
||||||
|
return targetRepository
|
||||||
|
.findOne(TargetSpecifications.hasControllerId(controllerId))
|
||||||
|
.map(JpaTarget::getAssignedDistributionSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
|
||||||
|
return targetRepository
|
||||||
|
.findOne(TargetSpecifications.hasControllerId(controllerId))
|
||||||
|
.map(JpaTarget::getInstalledDistributionSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = false)
|
||||||
|
public int deleteActionsByStatusAndLastModifiedBefore(final Set<Status> status, final long lastModified) {
|
||||||
|
if (status.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We use a native query here because Spring JPA does not support to specify a
|
||||||
|
* LIMIT clause on a DELETE statement. However, for this specific use case
|
||||||
|
* (action cleanup), we must specify a row limit to reduce the overall load on
|
||||||
|
* the database.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final int statusCount = status.size();
|
||||||
|
final Status[] statusArr = status.toArray(new Status[statusCount]);
|
||||||
|
|
||||||
|
final String queryStr = String.format(getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(database),
|
||||||
|
formatInClauseWithNumberKeys(statusCount));
|
||||||
|
final Query deleteQuery = entityManager.createNativeQuery(queryStr);
|
||||||
|
|
||||||
|
IntStream.range(0, statusCount)
|
||||||
|
.forEach(i -> deleteQuery.setParameter(String.valueOf(i), statusArr[i].ordinal()));
|
||||||
|
deleteQuery.setParameter("tenant", tenantAware.getCurrentTenant().toUpperCase());
|
||||||
|
deleteQuery.setParameter("last_modified_at", lastModified);
|
||||||
|
|
||||||
|
log.debug("Action cleanup: Executing the following (native) query: {}", deleteQuery);
|
||||||
|
return deleteQuery.executeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPendingCancellations(final Long targetId) {
|
||||||
|
// target access checked in assertTargetReadAllowed
|
||||||
|
assertTargetReadAllowed(targetId);
|
||||||
|
return actionRepository
|
||||||
|
.exists(ActionSpecifications.byTargetIdAndIsActiveAndStatus(targetId, Action.Status.CANCELING));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void cancelActionsForDistributionSet(final CancelationType cancelationType,
|
||||||
|
final DistributionSet distributionSet) {
|
||||||
|
actionRepository.findAll(ActionSpecifications
|
||||||
|
.byDistributionSetIdAndActiveAndStatusIsNot(distributionSet.getId(), Status.CANCELING))
|
||||||
|
.forEach(action -> {
|
||||||
|
try {
|
||||||
|
assertTargetUpdateAllowed(action);
|
||||||
|
cancelAction(action.getId());
|
||||||
|
log.debug("Action {} canceled", action.getId());
|
||||||
|
} catch (final InsufficientPermissionException e) {
|
||||||
|
log.trace("Could not cancel action {} due to insufficient permissions.", action.getId(), e);
|
||||||
|
} catch (final EntityNotFoundException e) {
|
||||||
|
log.trace("Could not cancel action {} due to entity not found exception.", action.getId(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (cancelationType == CancelationType.FORCE) {
|
||||||
|
actionRepository.findAll(ActionSpecifications.byDistributionSetIdAndActive(distributionSet.getId()))
|
||||||
|
.forEach(action -> {
|
||||||
|
try {
|
||||||
|
assertTargetUpdateAllowed(action);
|
||||||
|
forceQuitAction(action.getId());
|
||||||
|
log.debug("Action {} force canceled", action.getId());
|
||||||
|
} catch (final InsufficientPermissionException e) {
|
||||||
|
log.trace("Could not cancel action {} due to insufficient permissions.", action.getId(), e);
|
||||||
|
} catch (final EntityNotFoundException e) {
|
||||||
|
log.trace("Could not cancel action {} due to entity not found exception.", action.getId(),
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ActionRepository getActionRepository() {
|
||||||
|
return actionRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isActionsAutocloseEnabled() {
|
||||||
|
return getConfigValue(REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, Boolean.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Long, List<TargetWithActionType>> convertRequest(
|
||||||
|
final Collection<DeploymentRequest> deploymentRequests) {
|
||||||
|
return deploymentRequests.stream().collect(Collectors.groupingBy(DeploymentRequest::getDistributionSetId,
|
||||||
|
Collectors.mapping(DeploymentRequest::getTargetWithActionType, Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* split tIDs length into max entries in-statement because many database have
|
||||||
|
* constraint of max entries in in-statements e.g. Oracle with maximum 1000
|
||||||
|
* elements, so we need to split the entries here and execute multiple
|
||||||
|
* statements
|
||||||
|
*/
|
||||||
|
private static List<List<Long>> getTargetEntitiesAsChunks(final List<JpaTarget> targetEntities) {
|
||||||
|
return ListUtils.partition(targetEntities.stream().map(Target::getId).collect(Collectors.toList()),
|
||||||
|
Constants.MAX_ENTRIES_IN_STATEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DistributionSetAssignmentResult buildAssignmentResult(final JpaDistributionSet distributionSet,
|
||||||
|
final List<JpaAction> assignedActions, final int totalTargetsForAssignment) {
|
||||||
|
final int alreadyAssignedTargetsCount = totalTargetsForAssignment - assignedActions.size();
|
||||||
|
|
||||||
|
return new DistributionSetAssignmentResult(distributionSet, alreadyAssignedTargetsCount, assignedActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(final Database database) {
|
||||||
|
return QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.getOrDefault(database,
|
||||||
|
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatInClauseWithNumberKeys(final int count) {
|
||||||
|
return formatInClause(IntStream.range(0, count).mapToObj(String::valueOf).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatInClause(final Collection<String> elements) {
|
||||||
|
return "#" + String.join(",#", elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RetryTemplate createRetryTemplate() {
|
||||||
|
final RetryTemplate template = new RetryTemplate();
|
||||||
|
|
||||||
|
final FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
backOffPolicy.setBackOffPeriod(Constants.TX_RT_DELAY);
|
||||||
|
template.setBackOffPolicy(backOffPolicy);
|
||||||
|
|
||||||
|
final SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(Constants.TX_RT_MAX,
|
||||||
|
Collections.singletonMap(ConcurrencyFailureException.class, true));
|
||||||
|
template.setRetryPolicy(retryPolicy);
|
||||||
|
|
||||||
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DistributionSetAssignmentResult> assignDistributionSets(final String initiatedBy,
|
private List<DistributionSetAssignmentResult> assignDistributionSets(final String initiatedBy,
|
||||||
@@ -327,12 +739,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
return deploymentRequests;
|
return deploymentRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<Long, List<TargetWithActionType>> convertRequest(
|
|
||||||
final Collection<DeploymentRequest> deploymentRequests) {
|
|
||||||
return deploymentRequests.stream().collect(Collectors.groupingBy(DeploymentRequest::getDistributionSetId,
|
|
||||||
Collectors.mapping(DeploymentRequest::getTargetWithActionType, Collectors.toList())));
|
|
||||||
}
|
|
||||||
|
|
||||||
private DistributionSetAssignmentResult assignDistributionSetToTargetsWithRetry(final String initiatedBy,
|
private DistributionSetAssignmentResult assignDistributionSetToTargetsWithRetry(final String initiatedBy,
|
||||||
final Long dsId, final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
final Long dsId, final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
||||||
final AbstractDsAssignmentStrategy assignmentStrategy) {
|
final AbstractDsAssignmentStrategy assignmentStrategy) {
|
||||||
@@ -355,21 +761,14 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
* to {@link TargetUpdateStatus#IN_SYNC} <br/>
|
* to {@link TargetUpdateStatus#IN_SYNC} <br/>
|
||||||
* D. does not send a {@link TargetAssignDistributionSetEvent}.<br/>
|
* D. does not send a {@link TargetAssignDistributionSetEvent}.<br/>
|
||||||
*
|
*
|
||||||
* @param initiatedBy
|
* @param initiatedBy the username of the user who initiated the assignment
|
||||||
* the username of the user who initiated the assignment
|
* @param dsId the ID of the distribution set to assign
|
||||||
* @param dsId
|
* @param targetsWithActionType a list of all targets and their action type
|
||||||
* the ID of the distribution set to assign
|
* @param actionMessage an optional message to be written into the action status
|
||||||
* @param targetsWithActionType
|
* @param assignmentStrategy the assignment strategy (online /offline)
|
||||||
* a list of all targets and their action type
|
|
||||||
* @param actionMessage
|
|
||||||
* an optional message to be written into the action status
|
|
||||||
* @param assignmentStrategy
|
|
||||||
* the assignment strategy (online /offline)
|
|
||||||
* @return the assignment result
|
* @return the assignment result
|
||||||
*
|
* @throws IncompleteDistributionSetException if mandatory {@link SoftwareModuleType} are not assigned as
|
||||||
* @throws IncompleteDistributionSetException
|
* define by the {@link DistributionSetType}.
|
||||||
* if mandatory {@link SoftwareModuleType} are not assigned as
|
|
||||||
* define by the {@link DistributionSetType}.
|
|
||||||
*/
|
*/
|
||||||
private DistributionSetAssignmentResult assignDistributionSetToTargets(final String initiatedBy, final Long dsId,
|
private DistributionSetAssignmentResult assignDistributionSetToTargets(final String initiatedBy, final Long dsId,
|
||||||
final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
||||||
@@ -377,7 +776,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
final JpaDistributionSet distributionSet =
|
final JpaDistributionSet distributionSet =
|
||||||
(JpaDistributionSet) distributionSetManagement.getValidAndComplete(dsId);
|
(JpaDistributionSet) distributionSetManagement.getValidAndComplete(dsId);
|
||||||
|
|
||||||
if (((JpaDistributionSetManagement)distributionSetManagement).isImplicitLockApplicable(distributionSet)) {
|
if (((JpaDistributionSetManagement) distributionSetManagement).isImplicitLockApplicable(distributionSet)) {
|
||||||
// without new transaction DS changed event is not thrown
|
// without new transaction DS changed event is not thrown
|
||||||
DeploymentHelper.runInNewTransaction(txManager, "Implicit lock", status -> {
|
DeploymentHelper.runInNewTransaction(txManager, "Implicit lock", status -> {
|
||||||
distributionSetManagement.lock(distributionSet.getId());
|
distributionSetManagement.lock(distributionSet.getId());
|
||||||
@@ -446,24 +845,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
return new ArrayList<>(assignedActions.values());
|
return new ArrayList<>(assignedActions.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* split tIDs length into max entries in-statement because many database have
|
|
||||||
* constraint of max entries in in-statements e.g. Oracle with maximum 1000
|
|
||||||
* elements, so we need to split the entries here and execute multiple
|
|
||||||
* statements
|
|
||||||
*/
|
|
||||||
private static List<List<Long>> getTargetEntitiesAsChunks(final List<JpaTarget> targetEntities) {
|
|
||||||
return ListUtils.partition(targetEntities.stream().map(Target::getId).collect(Collectors.toList()),
|
|
||||||
Constants.MAX_ENTRIES_IN_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DistributionSetAssignmentResult buildAssignmentResult(final JpaDistributionSet distributionSet,
|
|
||||||
final List<JpaAction> assignedActions, final int totalTargetsForAssignment) {
|
|
||||||
final int alreadyAssignedTargetsCount = totalTargetsForAssignment - assignedActions.size();
|
|
||||||
|
|
||||||
return new DistributionSetAssignmentResult(distributionSet, alreadyAssignedTargetsCount, assignedActions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enforceMaxAssignmentsPerRequest(final int requestedActions) {
|
private void enforceMaxAssignmentsPerRequest(final int requestedActions) {
|
||||||
QuotaHelper.assertAssignmentRequestSizeQuota(requestedActions,
|
QuotaHelper.assertAssignmentRequestSizeQuota(requestedActions,
|
||||||
quotaManagement.getMaxTargetDistributionSetAssignmentsPerManualAssignment());
|
quotaManagement.getMaxTargetDistributionSetAssignmentsPerManualAssignment());
|
||||||
@@ -489,24 +870,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void cancelInactiveScheduledActionsForTargets(final List<Long> targetIds) {
|
|
||||||
if (!isMultiAssignmentsEnabled()) {
|
|
||||||
targetRepository.getAccessController().ifPresent(v -> {
|
|
||||||
if (targetRepository.count(AccessController.Operation.UPDATE,
|
|
||||||
TargetSpecifications.hasIdIn(targetIds)) != targetIds.size()) {
|
|
||||||
throw new EntityNotFoundException(Target.class, targetIds);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
actionRepository.switchStatus(Status.CANCELED, targetIds, false, Status.SCHEDULED);
|
|
||||||
} else {
|
|
||||||
log.debug("The Multi Assignments feature is enabled: No need to cancel inactive scheduled actions.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAssignedDistributionSetAndTargetUpdateStatus(final AbstractDsAssignmentStrategy assignmentStrategy,
|
private void setAssignedDistributionSetAndTargetUpdateStatus(final AbstractDsAssignmentStrategy assignmentStrategy,
|
||||||
final JpaDistributionSet set, final List<List<Long>> targetIdsChunks) {
|
final JpaDistributionSet set, final List<List<Long>> targetIdsChunks) {
|
||||||
final String currentUser = auditorProvider.getCurrentAuditor().orElse(null);
|
final String currentUser = auditorProvider.getCurrentAuditor().orElse(null);
|
||||||
@@ -581,112 +944,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
assignmentStrategy.sendTargetUpdatedEvents(set, targets);
|
assignmentStrategy.sendTargetUpdatedEvents(set, targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Action cancelAction(final long actionId) {
|
|
||||||
log.debug("cancelAction({})", actionId);
|
|
||||||
|
|
||||||
final JpaAction action = actionRepository.findById(actionId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
|
||||||
|
|
||||||
if (action.isCancelingOrCanceled()) {
|
|
||||||
throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled");
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTargetUpdateAllowed(action);
|
|
||||||
|
|
||||||
if (action.isActive()) {
|
|
||||||
log.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING);
|
|
||||||
action.setStatus(Status.CANCELING);
|
|
||||||
|
|
||||||
// document that the status has been retrieved
|
|
||||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
|
||||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "manual cancelation requested"));
|
|
||||||
final Action saveAction = actionRepository.save(action);
|
|
||||||
|
|
||||||
onlineDsAssignmentStrategy.cancelAssignment(action);
|
|
||||||
|
|
||||||
return saveAction;
|
|
||||||
} else {
|
|
||||||
throw new CancelActionNotAllowedException(action.getId() + " is not active and cannot be canceled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Action forceQuitAction(final long actionId) {
|
|
||||||
final JpaAction action = actionRepository.findById(actionId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
|
||||||
|
|
||||||
if (!action.isCancelingOrCanceled()) {
|
|
||||||
throw new ForceQuitActionNotAllowedException(
|
|
||||||
action.getId() + " is not canceled yet and cannot be force quit");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!action.isActive()) {
|
|
||||||
throw new ForceQuitActionNotAllowedException(action.getId() + " is not active and cannot be force quit");
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTargetUpdateAllowed(action);
|
|
||||||
|
|
||||||
log.warn("action ({}) was still active and has been force quite.", action);
|
|
||||||
|
|
||||||
// document that the status has been retrieved
|
|
||||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELED, System.currentTimeMillis(),
|
|
||||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "A force quit has been performed."));
|
|
||||||
|
|
||||||
DeploymentHelper.successCancellation(action, actionRepository, targetRepository);
|
|
||||||
|
|
||||||
return actionRepository.save(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startScheduledActionsByRolloutGroupParent(final long rolloutId, final long distributionSetId,
|
|
||||||
final Long rolloutGroupParentId) {
|
|
||||||
while (DeploymentHelper.runInNewTransaction(
|
|
||||||
txManager,
|
|
||||||
"startScheduledActions-" + rolloutId,
|
|
||||||
status -> {
|
|
||||||
final PageRequest pageRequest = PageRequest.of(0, ACTION_PAGE_LIMIT);
|
|
||||||
final Page<Action> groupScheduledActions;
|
|
||||||
if (rolloutGroupParentId == null) {
|
|
||||||
groupScheduledActions = actionRepository.findByRolloutIdAndRolloutGroupParentIsNullAndStatus(pageRequest, rolloutId, Action.Status.SCHEDULED);
|
|
||||||
} else {
|
|
||||||
groupScheduledActions = actionRepository.findByRolloutIdAndRolloutGroupParentIdAndStatus(pageRequest, rolloutId, rolloutGroupParentId, Action.Status.SCHEDULED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (groupScheduledActions.getContent().isEmpty()) {
|
|
||||||
return 0L;
|
|
||||||
} else {
|
|
||||||
// self invocation won't check @PreAuthorize but it is already checked for the method
|
|
||||||
startScheduledActions(groupScheduledActions.getContent());
|
|
||||||
return groupScheduledActions.getTotalElements();
|
|
||||||
}
|
|
||||||
}) > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startScheduledActions(final List<Action> rolloutGroupActions) {
|
|
||||||
// Close actions already assigned and collect pending assignments
|
|
||||||
final List<JpaAction> pendingTargetAssignments = rolloutGroupActions.stream()
|
|
||||||
.map(JpaAction.class::cast)
|
|
||||||
.map(this::closeActionIfSetWasAlreadyAssigned)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList();
|
|
||||||
if (pendingTargetAssignments.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// check if old actions needs to be canceled first
|
|
||||||
final List<Action> newTargetAssignments = startScheduledActionsAndHandleOpenCancellationFirst(pendingTargetAssignments);
|
|
||||||
if (!newTargetAssignments.isEmpty()) {
|
|
||||||
onlineDsAssignmentStrategy.sendDeploymentEvents(newTargetAssignments.get(0).getDistributionSet().getId(), newTargetAssignments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JpaAction closeActionIfSetWasAlreadyAssigned(final JpaAction action) {
|
private JpaAction closeActionIfSetWasAlreadyAssigned(final JpaAction action) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
if (isMultiAssignmentsEnabled()) {
|
||||||
return action;
|
return action;
|
||||||
@@ -764,221 +1021,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
actionStatusRepository.save(actionStatus);
|
actionStatusRepository.save(actionStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Action> findAction(final long actionId) {
|
|
||||||
return actionRepository.findById(actionId)
|
|
||||||
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())))
|
|
||||||
.map(JpaAction.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Action> findActionWithDetails(final long actionId) {
|
|
||||||
return actionRepository.findWithDetailsById(actionId)
|
|
||||||
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<Action> findActionsByTarget(final String controllerId, final Pageable pageable) {
|
|
||||||
assertTargetReadAllowed(controllerId);
|
|
||||||
return actionRepository.findAll(ActionSpecifications.byTargetControllerId(controllerId), pageable)
|
|
||||||
.map(Action.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<Action> findActionsByTarget(final String rsqlParam, final String controllerId,
|
|
||||||
final Pageable pageable) {
|
|
||||||
assertTargetReadAllowed(controllerId);
|
|
||||||
|
|
||||||
final List<Specification<JpaAction>> specList = Arrays.asList(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database),
|
|
||||||
ActionSpecifications.byTargetControllerId(controllerId));
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(actionRepository, pageable, specList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
|
||||||
assertTargetReadAllowed(controllerId);
|
|
||||||
return actionRepository
|
|
||||||
.findAll(ActionSpecifications.byTargetControllerIdAndActive(controllerId, true), pageable)
|
|
||||||
.map(Action.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<Action> findInActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
|
||||||
assertTargetReadAllowed(controllerId);
|
|
||||||
return actionRepository
|
|
||||||
.findAll(ActionSpecifications.byTargetControllerIdAndActive(controllerId, false), pageable)
|
|
||||||
.map(Action.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Action> findActiveActionsWithHighestWeight(final String controllerId, final int maxActionCount) {
|
|
||||||
assertTargetReadAllowed(controllerId);
|
|
||||||
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countActionsByTarget(final String controllerId) {
|
|
||||||
assertTargetReadAllowed(controllerId);
|
|
||||||
return actionRepository.countByTargetControllerId(controllerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countActionsByTarget(final String rsqlParam, final String controllerId) {
|
|
||||||
assertTargetReadAllowed(controllerId);
|
|
||||||
|
|
||||||
final List<Specification<JpaAction>> specList = Arrays.asList(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database),
|
|
||||||
ActionSpecifications.byTargetControllerId(controllerId));
|
|
||||||
|
|
||||||
return JpaManagementHelper.countBySpec(actionRepository, specList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Action forceTargetAction(final long actionId) {
|
|
||||||
final JpaAction action = actionRepository.findById(actionId).map(this::assertTargetUpdateAllowed)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
|
||||||
|
|
||||||
if (!action.isForcedOrTimeForced()) {
|
|
||||||
action.setActionType(ActionType.FORCED);
|
|
||||||
return actionRepository.save(action);
|
|
||||||
}
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<ActionStatus> findActionStatusByAction(final Pageable pageReq, final long actionId) {
|
|
||||||
assertActionExistsAndAccessible(actionId);
|
|
||||||
|
|
||||||
return actionStatusRepository.findByActionId(pageReq, actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countActionStatusByAction(final long actionId) {
|
|
||||||
assertActionExistsAndAccessible(actionId);
|
|
||||||
|
|
||||||
return actionStatusRepository.countByActionId(actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// action is already got and there are checked read permissions - do not check
|
|
||||||
// permissions
|
|
||||||
// and UI which is to be removed
|
|
||||||
@Override
|
|
||||||
public Page<String> findMessagesByActionStatusId(final Pageable pageable, final long actionStatusId) {
|
|
||||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
|
||||||
|
|
||||||
final CriteriaQuery<String> msgQuery = cb.createQuery(String.class);
|
|
||||||
final Root<JpaActionStatus> as = msgQuery.from(JpaActionStatus.class);
|
|
||||||
final ListJoin<JpaActionStatus, String> join = as.joinList("messages", JoinType.LEFT);
|
|
||||||
final CriteriaQuery<String> selMsgQuery = msgQuery.select(join);
|
|
||||||
selMsgQuery.where(cb.equal(as.get(JpaActionStatus_.id), actionStatusId));
|
|
||||||
|
|
||||||
final List<String> result = new ArrayList<>(entityManager.createQuery(selMsgQuery)
|
|
||||||
.setFirstResult((int) pageable.getOffset()).setMaxResults(pageable.getPageSize()).getResultList());
|
|
||||||
|
|
||||||
return new PageImpl<>(result, pageable, result.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countActionsAll() {
|
|
||||||
return actionRepository.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countActions(final String rsqlParam) {
|
|
||||||
final List<Specification<JpaAction>> specList = List.of(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database));
|
|
||||||
return JpaManagementHelper.countBySpec(actionRepository, specList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<Action> findActionsAll(final Pageable pageable) {
|
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, pageable, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<Action> findActions(final String rsqlParam, final Pageable pageable) {
|
|
||||||
final List<Specification<JpaAction>> specList = List.of(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database));
|
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, pageable, specList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
|
|
||||||
return targetRepository
|
|
||||||
.findOne(TargetSpecifications.hasControllerId(controllerId))
|
|
||||||
.map(JpaTarget::getAssignedDistributionSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
|
|
||||||
return targetRepository
|
|
||||||
.findOne(TargetSpecifications.hasControllerId(controllerId))
|
|
||||||
.map(JpaTarget::getInstalledDistributionSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(readOnly = false)
|
|
||||||
public int deleteActionsByStatusAndLastModifiedBefore(final Set<Status> status, final long lastModified) {
|
|
||||||
if (status.isEmpty()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* We use a native query here because Spring JPA does not support to specify a
|
|
||||||
* LIMIT clause on a DELETE statement. However, for this specific use case
|
|
||||||
* (action cleanup), we must specify a row limit to reduce the overall load on
|
|
||||||
* the database.
|
|
||||||
*/
|
|
||||||
|
|
||||||
final int statusCount = status.size();
|
|
||||||
final Status[] statusArr = status.toArray(new Status[statusCount]);
|
|
||||||
|
|
||||||
final String queryStr = String.format(getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(database),
|
|
||||||
formatInClauseWithNumberKeys(statusCount));
|
|
||||||
final Query deleteQuery = entityManager.createNativeQuery(queryStr);
|
|
||||||
|
|
||||||
IntStream.range(0, statusCount)
|
|
||||||
.forEach(i -> deleteQuery.setParameter(String.valueOf(i), statusArr[i].ordinal()));
|
|
||||||
deleteQuery.setParameter("tenant", tenantAware.getCurrentTenant().toUpperCase());
|
|
||||||
deleteQuery.setParameter("last_modified_at", lastModified);
|
|
||||||
|
|
||||||
log.debug("Action cleanup: Executing the following (native) query: {}", deleteQuery);
|
|
||||||
return deleteQuery.executeUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPendingCancellations(final Long targetId) {
|
|
||||||
// target access checked in assertTargetReadAllowed
|
|
||||||
assertTargetReadAllowed(targetId);
|
|
||||||
return actionRepository
|
|
||||||
.exists(ActionSpecifications.byTargetIdAndIsActiveAndStatus(targetId, Action.Status.CANCELING));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(final Database database) {
|
|
||||||
return QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.getOrDefault(database,
|
|
||||||
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String formatInClauseWithNumberKeys(final int count) {
|
|
||||||
return formatInClause(IntStream.range(0, count).mapToObj(String::valueOf).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String formatInClause(final Collection<String> elements) {
|
|
||||||
return "#" + String.join(",#", elements);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ActionRepository getActionRepository() {
|
|
||||||
return actionRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isActionsAutocloseEnabled() {
|
|
||||||
return getConfigValue(REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, Boolean.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isMultiAssignmentsEnabled() {
|
private boolean isMultiAssignmentsEnabled() {
|
||||||
return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
||||||
.isMultiAssignmentsEnabled();
|
.isMultiAssignmentsEnabled();
|
||||||
@@ -994,54 +1036,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue());
|
.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RetryTemplate createRetryTemplate() {
|
|
||||||
final RetryTemplate template = new RetryTemplate();
|
|
||||||
|
|
||||||
final FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
|
||||||
backOffPolicy.setBackOffPeriod(Constants.TX_RT_DELAY);
|
|
||||||
template.setBackOffPolicy(backOffPolicy);
|
|
||||||
|
|
||||||
final SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(Constants.TX_RT_MAX,
|
|
||||||
Collections.singletonMap(ConcurrencyFailureException.class, true));
|
|
||||||
template.setRetryPolicy(retryPolicy);
|
|
||||||
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void cancelActionsForDistributionSet(final CancelationType cancelationType,
|
|
||||||
final DistributionSet distributionSet) {
|
|
||||||
actionRepository.findAll(ActionSpecifications
|
|
||||||
.byDistributionSetIdAndActiveAndStatusIsNot(distributionSet.getId(), Status.CANCELING))
|
|
||||||
.forEach(action -> {
|
|
||||||
try {
|
|
||||||
assertTargetUpdateAllowed(action);
|
|
||||||
cancelAction(action.getId());
|
|
||||||
log.debug("Action {} canceled", action.getId());
|
|
||||||
} catch (final InsufficientPermissionException e) {
|
|
||||||
log.trace("Could not cancel action {} due to insufficient permissions.", action.getId(), e);
|
|
||||||
} catch (final EntityNotFoundException e) {
|
|
||||||
log.trace("Could not cancel action {} due to entity not found exception.", action.getId(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (cancelationType == CancelationType.FORCE) {
|
|
||||||
actionRepository.findAll(ActionSpecifications.byDistributionSetIdAndActive(distributionSet.getId()))
|
|
||||||
.forEach(action -> {
|
|
||||||
try {
|
|
||||||
assertTargetUpdateAllowed(action);
|
|
||||||
forceQuitAction(action.getId());
|
|
||||||
log.debug("Action {} force canceled", action.getId());
|
|
||||||
} catch (final InsufficientPermissionException e) {
|
|
||||||
log.trace("Could not cancel action {} due to insufficient permissions.", action.getId(), e);
|
|
||||||
} catch (final EntityNotFoundException e) {
|
|
||||||
log.trace("Could not cancel action {} due to entity not found exception.", action.getId(),
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertTargetReadAllowed(final Long targetId) {
|
private void assertTargetReadAllowed(final Long targetId) {
|
||||||
if (!targetRepository.existsById(targetId)) {
|
if (!targetRepository.existsById(targetId)) {
|
||||||
throw new EntityNotFoundException(Target.class, targetId);
|
throw new EntityNotFoundException(Target.class, targetId);
|
||||||
|
|||||||
@@ -97,6 +97,26 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DistributionSetInvalidationCount countEntitiesForInvalidation(
|
||||||
|
final DistributionSetInvalidation distributionSetInvalidation) {
|
||||||
|
return systemSecurityContext.runAsSystem(() -> {
|
||||||
|
final Collection<Long> setIds = distributionSetInvalidation.getDistributionSetIds();
|
||||||
|
final long rolloutsCount = shouldRolloutsBeCanceled(distributionSetInvalidation.getCancelationType(),
|
||||||
|
distributionSetInvalidation.isCancelRollouts()) ? countRolloutsForInvalidation(setIds) : 0;
|
||||||
|
final long autoAssignmentsCount = countAutoAssignmentsForInvalidation(setIds);
|
||||||
|
final long actionsCount = countActionsForInvalidation(setIds,
|
||||||
|
distributionSetInvalidation.getCancelationType());
|
||||||
|
|
||||||
|
return new DistributionSetInvalidationCount(rolloutsCount, autoAssignmentsCount, actionsCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldRolloutsBeCanceled(final CancelationType cancelationType,
|
||||||
|
final boolean cancelRollouts) {
|
||||||
|
return cancelationType != CancelationType.NONE || cancelRollouts;
|
||||||
|
}
|
||||||
|
|
||||||
private void invalidateDistributionSetsInTransaction(final DistributionSetInvalidation distributionSetInvalidation,
|
private void invalidateDistributionSetsInTransaction(final DistributionSetInvalidation distributionSetInvalidation,
|
||||||
final String tenant) {
|
final String tenant) {
|
||||||
DeploymentHelper.runInNewTransaction(txManager, tenant + "-invalidateDS", status -> {
|
DeploymentHelper.runInNewTransaction(txManager, tenant + "-invalidateDS", status -> {
|
||||||
@@ -135,26 +155,6 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldRolloutsBeCanceled(final CancelationType cancelationType,
|
|
||||||
final boolean cancelRollouts) {
|
|
||||||
return cancelationType != CancelationType.NONE || cancelRollouts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DistributionSetInvalidationCount countEntitiesForInvalidation(
|
|
||||||
final DistributionSetInvalidation distributionSetInvalidation) {
|
|
||||||
return systemSecurityContext.runAsSystem(() -> {
|
|
||||||
final Collection<Long> setIds = distributionSetInvalidation.getDistributionSetIds();
|
|
||||||
final long rolloutsCount = shouldRolloutsBeCanceled(distributionSetInvalidation.getCancelationType(),
|
|
||||||
distributionSetInvalidation.isCancelRollouts()) ? countRolloutsForInvalidation(setIds) : 0;
|
|
||||||
final long autoAssignmentsCount = countAutoAssignmentsForInvalidation(setIds);
|
|
||||||
final long actionsCount = countActionsForInvalidation(setIds,
|
|
||||||
distributionSetInvalidation.getCancelationType());
|
|
||||||
|
|
||||||
return new DistributionSetInvalidationCount(rolloutsCount, autoAssignmentsCount, actionsCount);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private long countRolloutsForInvalidation(final Collection<Long> setIds) {
|
private long countRolloutsForInvalidation(final Collection<Long> setIds) {
|
||||||
return setIds.stream().mapToLong(rolloutManagement::countByDistributionSetIdAndRolloutIsStoppable).sum();
|
return setIds.stream().mapToLong(rolloutManagement::countByDistributionSetIdAndRolloutIsStoppable).sum();
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,6 @@ import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
|||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagCreate;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagCreate;
|
||||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||||
@@ -49,7 +48,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of {@link TargetTagManagement}.
|
* JPA implementation of {@link TargetTagManagement}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
@@ -76,22 +74,11 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public DistributionSetTag update(final TagUpdate u) {
|
public List<DistributionSetTag> create(final Collection<TagCreate> dst) {
|
||||||
final GenericTagUpdate update = (GenericTagUpdate) u;
|
final List<JpaDistributionSetTag> toCreate = dst.stream().map(JpaTagCreate.class::cast)
|
||||||
|
.map(JpaTagCreate::buildDistributionSetTag).toList();
|
||||||
final JpaDistributionSetTag tag = distributionSetTagRepository.findById(update.getId())
|
return Collections
|
||||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, update.getId()));
|
.unmodifiableList(distributionSetTagRepository.saveAll(AccessController.Operation.CREATE, toCreate));
|
||||||
|
|
||||||
update.getName().ifPresent(tag::setName);
|
|
||||||
update.getDescription().ifPresent(tag::setDescription);
|
|
||||||
update.getColour().ifPresent(tag::setColour);
|
|
||||||
|
|
||||||
return distributionSetTagRepository.save(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<DistributionSetTag> getByName(final String name) {
|
|
||||||
return distributionSetTagRepository.findByNameEquals(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -107,47 +94,30 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public List<DistributionSetTag> create(final Collection<TagCreate> dst) {
|
public DistributionSetTag update(final TagUpdate u) {
|
||||||
final List<JpaDistributionSetTag> toCreate = dst.stream().map(JpaTagCreate.class::cast)
|
final GenericTagUpdate update = (GenericTagUpdate) u;
|
||||||
.map(JpaTagCreate::buildDistributionSetTag).toList();
|
|
||||||
return Collections
|
final JpaDistributionSetTag tag = distributionSetTagRepository.findById(update.getId())
|
||||||
.unmodifiableList(distributionSetTagRepository.saveAll(AccessController.Operation.CREATE, toCreate));
|
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, update.getId()));
|
||||||
|
|
||||||
|
update.getName().ifPresent(tag::setName);
|
||||||
|
update.getDescription().ifPresent(tag::setDescription);
|
||||||
|
update.getColour().ifPresent(tag::setColour);
|
||||||
|
|
||||||
|
return distributionSetTagRepository.save(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long count() {
|
||||||
|
return distributionSetTagRepository.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public void delete(final String tagName) {
|
public void delete(final long id) {
|
||||||
final JpaDistributionSetTag dsTag = distributionSetTagRepository
|
distributionSetTagRepository.deleteById(id);
|
||||||
.findOne(DistributionSetTagSpecifications.byName(tagName))
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName));
|
|
||||||
|
|
||||||
distributionSetTagRepository.delete(dsTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<DistributionSetTag> findAll(final Pageable pageable) {
|
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTagRepository, pageable, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<DistributionSetTag> findByRsql(final Pageable pageable, final String rsqlParam) {
|
|
||||||
final Specification<JpaDistributionSetTag> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTagFields.class,
|
|
||||||
virtualPropertyReplacer, database);
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, pageable,
|
|
||||||
Collections.singletonList(spec));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<DistributionSetTag> findByDistributionSet(final Pageable pageable, final long distributionSetId) {
|
|
||||||
if (!distributionSetRepository.existsById(distributionSetId)) {
|
|
||||||
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, pageable,
|
|
||||||
Collections.singletonList(TagSpecification.ofDistributionSet(distributionSetId)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -170,26 +140,54 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
|||||||
return Collections.unmodifiableList(distributionSetTagRepository.findAllById(ids));
|
return Collections.unmodifiableList(distributionSetTagRepository.findAllById(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists(final long id) {
|
||||||
|
return distributionSetTagRepository.existsById(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<DistributionSetTag> get(final long id) {
|
public Optional<DistributionSetTag> get(final long id) {
|
||||||
return distributionSetTagRepository.findById(id).map(DistributionSetTag.class::cast);
|
return distributionSetTagRepository.findById(id).map(DistributionSetTag.class::cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<DistributionSetTag> findAll(final Pageable pageable) {
|
||||||
|
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTagRepository, pageable, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<DistributionSetTag> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||||
|
final Specification<JpaDistributionSetTag> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTagFields.class,
|
||||||
|
virtualPropertyReplacer, database);
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, pageable,
|
||||||
|
Collections.singletonList(spec));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public void delete(final long id) {
|
public void delete(final String tagName) {
|
||||||
distributionSetTagRepository.deleteById(id);
|
final JpaDistributionSetTag dsTag = distributionSetTagRepository
|
||||||
|
.findOne(DistributionSetTagSpecifications.byName(tagName))
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName));
|
||||||
|
|
||||||
|
distributionSetTagRepository.delete(dsTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists(final long id) {
|
public Optional<DistributionSetTag> getByName(final String name) {
|
||||||
return distributionSetTagRepository.existsById(id);
|
return distributionSetTagRepository.findByNameEquals(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long count() {
|
public Page<DistributionSetTag> findByDistributionSet(final Pageable pageable, final long distributionSetId) {
|
||||||
return distributionSetTagRepository.count();
|
if (!distributionSetRepository.existsById(distributionSetId)) {
|
||||||
|
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, pageable,
|
||||||
|
Collections.singletonList(TagSpecification.ofDistributionSet(distributionSetId)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of {@link DistributionSetTypeManagement}.
|
* JPA implementation of {@link DistributionSetTypeManagement}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
@@ -92,6 +91,72 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
this.quotaManagement = quotaManagement;
|
this.quotaManagement = quotaManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<DistributionSetType> getByKey(final String key) {
|
||||||
|
return distributionSetTypeRepository
|
||||||
|
.findOne(DistributionSetTypeSpecification.byKey(key)).map(DistributionSetType.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<DistributionSetType> getByName(final String name) {
|
||||||
|
return distributionSetTypeRepository
|
||||||
|
.findOne(DistributionSetTypeSpecification.byName(name)).map(DistributionSetType.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public DistributionSetType assignOptionalSoftwareModuleTypes(final long id,
|
||||||
|
final Collection<Long> softwareModulesTypeIds) {
|
||||||
|
return assignSoftwareModuleTypes(id, softwareModulesTypeIds, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public DistributionSetType assignMandatorySoftwareModuleTypes(final long id,
|
||||||
|
final Collection<Long> softwareModuleTypeIds) {
|
||||||
|
return assignSoftwareModuleTypes(id, softwareModuleTypeIds, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public DistributionSetType unassignSoftwareModuleType(final long id, final long softwareModuleTypeId) {
|
||||||
|
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(id);
|
||||||
|
|
||||||
|
checkDistributionSetTypeNotAssigned(id);
|
||||||
|
|
||||||
|
type.removeModuleType(softwareModuleTypeId);
|
||||||
|
|
||||||
|
return distributionSetTypeRepository.save(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public List<DistributionSetType> create(final Collection<DistributionSetTypeCreate> types) {
|
||||||
|
final List<JpaDistributionSetType> typesToCreate = types.stream().map(JpaDistributionSetTypeCreate.class::cast)
|
||||||
|
.map(JpaDistributionSetTypeCreate::build).toList();
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(
|
||||||
|
distributionSetTypeRepository.saveAll(AccessController.Operation.CREATE, typesToCreate));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public DistributionSetType create(final DistributionSetTypeCreate c) {
|
||||||
|
final JpaDistributionSetType distributionSetType = ((JpaDistributionSetTypeCreate) c).build();
|
||||||
|
|
||||||
|
return distributionSetTypeRepository.save(AccessController.Operation.CREATE, distributionSetType);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -130,15 +195,66 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
return distributionSetTypeRepository.save(type);
|
return distributionSetTypeRepository.save(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addModuleTypes(final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
@Override
|
||||||
final Function<SoftwareModuleType, JpaDistributionSetType> addModuleTypeCallback) {
|
public long count() {
|
||||||
final Set<Long> smTypeIdsToAdd = updatedSmTypeIds.stream().filter(id -> !currentSmTypeIds.contains(id))
|
return distributionSetTypeRepository.count(DistributionSetTypeSpecification.isNotDeleted());
|
||||||
.collect(Collectors.toSet());
|
}
|
||||||
if (!CollectionUtils.isEmpty(smTypeIdsToAdd)) {
|
|
||||||
softwareModuleTypeRepository.findAllById(smTypeIdsToAdd).forEach(addModuleTypeCallback::apply);
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void delete(final long id) {
|
||||||
|
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, id));
|
||||||
|
|
||||||
|
unassignDsTypeFromTargetTypes(id);
|
||||||
|
|
||||||
|
if (distributionSetRepository.countByTypeId(id) > 0) {
|
||||||
|
toDelete.setDeleted(true);
|
||||||
|
distributionSetTypeRepository.save(AccessController.Operation.DELETE, toDelete);
|
||||||
|
} else {
|
||||||
|
distributionSetTypeRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void delete(final Collection<Long> ids) {
|
||||||
|
distributionSetTypeRepository.deleteAllById(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DistributionSetType> get(final Collection<Long> ids) {
|
||||||
|
return Collections.unmodifiableList(distributionSetTypeRepository.findAllById(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists(final long id) {
|
||||||
|
return distributionSetTypeRepository.existsById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<DistributionSetType> get(final long id) {
|
||||||
|
return distributionSetTypeRepository.findById(id).map(DistributionSetType.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<DistributionSetType> findAll(final Pageable pageable) {
|
||||||
|
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTypeRepository, pageable, List.of(
|
||||||
|
DistributionSetTypeSpecification.isNotDeleted()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<DistributionSetType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, pageable, List.of(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTypeFields.class, virtualPropertyReplacer,
|
||||||
|
database),
|
||||||
|
DistributionSetTypeSpecification.isNotDeleted()));
|
||||||
|
}
|
||||||
|
|
||||||
private static void removeModuleTypes(final Collection<Long> currentSmTypeIds,
|
private static void removeModuleTypes(final Collection<Long> currentSmTypeIds,
|
||||||
final Collection<Long> updatedSmTypeIds,
|
final Collection<Long> updatedSmTypeIds,
|
||||||
final LongFunction<JpaDistributionSetType> removeModuleTypeCallback) {
|
final LongFunction<JpaDistributionSetType> removeModuleTypeCallback) {
|
||||||
@@ -149,22 +265,17 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static boolean hasModuleChanges(final GenericDistributionSetTypeUpdate update) {
|
||||||
@Transactional
|
return update.getOptional().isPresent() || update.getMandatory().isPresent();
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public DistributionSetType assignMandatorySoftwareModuleTypes(final long id,
|
|
||||||
final Collection<Long> softwareModuleTypeIds) {
|
|
||||||
return assignSoftwareModuleTypes(id, softwareModuleTypeIds, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void addModuleTypes(final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
||||||
@Transactional
|
final Function<SoftwareModuleType, JpaDistributionSetType> addModuleTypeCallback) {
|
||||||
@Retryable(include = {
|
final Set<Long> smTypeIdsToAdd = updatedSmTypeIds.stream().filter(id -> !currentSmTypeIds.contains(id))
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
.collect(Collectors.toSet());
|
||||||
public DistributionSetType assignOptionalSoftwareModuleTypes(final long id,
|
if (!CollectionUtils.isEmpty(smTypeIdsToAdd)) {
|
||||||
final Collection<Long> softwareModulesTypeIds) {
|
softwareModuleTypeRepository.findAllById(smTypeIdsToAdd).forEach(addModuleTypeCallback::apply);
|
||||||
return assignSoftwareModuleTypes(id, softwareModulesTypeIds, false);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DistributionSetType assignSoftwareModuleTypes(
|
private DistributionSetType assignSoftwareModuleTypes(
|
||||||
@@ -189,14 +300,10 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
/**
|
/**
|
||||||
* Enforces the quota specifying the maximum number of
|
* Enforces the quota specifying the maximum number of
|
||||||
* {@link SoftwareModuleType}s per {@link DistributionSetType}.
|
* {@link SoftwareModuleType}s per {@link DistributionSetType}.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id of the distribution set type
|
||||||
* of the distribution set type
|
* @param requested number of software module types to check
|
||||||
* @param requested
|
* @throws AssignmentQuotaExceededException if the software module type quota is exceeded
|
||||||
* number of software module types to check
|
|
||||||
*
|
|
||||||
* @throws AssignmentQuotaExceededException
|
|
||||||
* if the software module type quota is exceeded
|
|
||||||
*/
|
*/
|
||||||
private void assertSoftwareModuleTypeQuota(final long id, final int requested) {
|
private void assertSoftwareModuleTypeQuota(final long id, final int requested) {
|
||||||
QuotaHelper.assertAssignmentQuota(id, requested,
|
QuotaHelper.assertAssignmentQuota(id, requested,
|
||||||
@@ -204,79 +311,6 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
DistributionSetType.class, distributionSetTypeRepository::countSmTypesById);
|
DistributionSetType.class, distributionSetTypeRepository::countSmTypesById);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public DistributionSetType unassignSoftwareModuleType(final long id, final long softwareModuleTypeId) {
|
|
||||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(id);
|
|
||||||
|
|
||||||
checkDistributionSetTypeNotAssigned(id);
|
|
||||||
|
|
||||||
type.removeModuleType(softwareModuleTypeId);
|
|
||||||
|
|
||||||
return distributionSetTypeRepository.save(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<DistributionSetType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, pageable, List.of(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTypeFields.class, virtualPropertyReplacer,
|
|
||||||
database),
|
|
||||||
DistributionSetTypeSpecification.isNotDeleted()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<DistributionSetType> findAll(final Pageable pageable) {
|
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTypeRepository, pageable, List.of(
|
|
||||||
DistributionSetTypeSpecification.isNotDeleted()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count() {
|
|
||||||
return distributionSetTypeRepository.count(DistributionSetTypeSpecification.isNotDeleted());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<DistributionSetType> getByName(final String name) {
|
|
||||||
return distributionSetTypeRepository
|
|
||||||
.findOne(DistributionSetTypeSpecification.byName(name)).map(DistributionSetType.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<DistributionSetType> getByKey(final String key) {
|
|
||||||
return distributionSetTypeRepository
|
|
||||||
.findOne(DistributionSetTypeSpecification.byKey(key)).map(DistributionSetType.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public DistributionSetType create(final DistributionSetTypeCreate c) {
|
|
||||||
final JpaDistributionSetType distributionSetType = ((JpaDistributionSetTypeCreate) c).build();
|
|
||||||
|
|
||||||
return distributionSetTypeRepository.save(AccessController.Operation.CREATE, distributionSetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void delete(final long id) {
|
|
||||||
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(id)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, id));
|
|
||||||
|
|
||||||
unassignDsTypeFromTargetTypes(id);
|
|
||||||
|
|
||||||
if (distributionSetRepository.countByTypeId(id) > 0) {
|
|
||||||
toDelete.setDeleted(true);
|
|
||||||
distributionSetTypeRepository.save(AccessController.Operation.DELETE, toDelete);
|
|
||||||
} else {
|
|
||||||
distributionSetTypeRepository.deleteById(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unassignDsTypeFromTargetTypes(final long typeId) {
|
private void unassignDsTypeFromTargetTypes(final long typeId) {
|
||||||
final List<JpaTargetType> targetTypesByDsType = targetTypeRepository.findByDsType(typeId);
|
final List<JpaTargetType> targetTypesByDsType = targetTypeRepository.findByDsType(typeId);
|
||||||
targetTypesByDsType.forEach(targetType -> {
|
targetTypesByDsType.forEach(targetType -> {
|
||||||
@@ -285,54 +319,15 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public List<DistributionSetType> create(final Collection<DistributionSetTypeCreate> types) {
|
|
||||||
final List<JpaDistributionSetType> typesToCreate = types.stream().map(JpaDistributionSetTypeCreate.class::cast)
|
|
||||||
.map(JpaDistributionSetTypeCreate::build).toList();
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(
|
|
||||||
distributionSetTypeRepository.saveAll(AccessController.Operation.CREATE, typesToCreate));
|
|
||||||
}
|
|
||||||
|
|
||||||
private JpaDistributionSetType findDistributionSetTypeAndThrowExceptionIfNotFound(final Long setId) {
|
private JpaDistributionSetType findDistributionSetTypeAndThrowExceptionIfNotFound(final Long setId) {
|
||||||
return (JpaDistributionSetType) get(setId)
|
return (JpaDistributionSetType) get(setId)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, setId));
|
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, setId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasModuleChanges(final GenericDistributionSetTypeUpdate update) {
|
|
||||||
return update.getOptional().isPresent() || update.getMandatory().isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkDistributionSetTypeNotAssigned(final Long id) {
|
private void checkDistributionSetTypeNotAssigned(final Long id) {
|
||||||
if (distributionSetRepository.countByTypeId(id) > 0) {
|
if (distributionSetRepository.countByTypeId(id) > 0) {
|
||||||
throw new EntityReadOnlyException(String.format(
|
throw new EntityReadOnlyException(String.format(
|
||||||
"Distribution set type %s is already assigned to distribution sets and cannot be changed!", id));
|
"Distribution set type %s is already assigned to distribution sets and cannot be changed!", id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void delete(final Collection<Long> ids) {
|
|
||||||
distributionSetTypeRepository.deleteAllById(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DistributionSetType> get(final Collection<Long> ids) {
|
|
||||||
return Collections.unmodifiableList(distributionSetTypeRepository.findAllById(ids));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<DistributionSetType> get(final long id) {
|
|
||||||
return distributionSetTypeRepository.findById(id).map(DistributionSetType.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean exists(final long id) {
|
|
||||||
return distributionSetTypeRepository.existsById(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,10 +91,10 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
private final Database database;
|
private final Database database;
|
||||||
|
|
||||||
public JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
public JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||||
final TargetRepository targetRepository, final EntityManager entityManager,
|
final TargetRepository targetRepository, final EntityManager entityManager,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
||||||
final Database database) {
|
final Database database) {
|
||||||
this.rolloutGroupRepository = rolloutGroupRepository;
|
this.rolloutGroupRepository = rolloutGroupRepository;
|
||||||
this.rolloutRepository = rolloutRepository;
|
this.rolloutRepository = rolloutRepository;
|
||||||
this.actionRepository = actionRepository;
|
this.actionRepository = actionRepository;
|
||||||
@@ -105,37 +105,6 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<RolloutGroup> get(final long rolloutGroupId) {
|
|
||||||
return rolloutGroupRepository.findById(rolloutGroupId).map(RolloutGroup.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<RolloutGroup> findByRollout(final Pageable pageable, final long rolloutId) {
|
|
||||||
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
|
||||||
|
|
||||||
return JpaManagementHelper.convertPage(rolloutGroupRepository.findByRolloutId(rolloutId, pageable), pageable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<RolloutGroup> findByRolloutAndRsql(final Pageable pageable, final long rolloutId,
|
|
||||||
final String rsqlParam) {
|
|
||||||
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
|
||||||
|
|
||||||
final List<Specification<JpaRolloutGroup>> specList = Arrays.asList(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, RolloutGroupFields.class, virtualPropertyReplacer,
|
|
||||||
database),
|
|
||||||
(root, query, cb) -> cb.equal(root.get(JpaRolloutGroup_.rollout).get(JpaRollout_.id), rolloutId));
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(rolloutGroupRepository, pageable, specList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void throwEntityNotFoundExceptionIfRolloutDoesNotExist(final Long rolloutId) {
|
|
||||||
if (!rolloutRepository.existsById(rolloutId)) {
|
|
||||||
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<RolloutGroup> findByRolloutWithDetailedStatus(final Pageable pageable, final long rolloutId) {
|
public Page<RolloutGroup> findByRolloutWithDetailedStatus(final Pageable pageable, final long rolloutId) {
|
||||||
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
||||||
@@ -154,7 +123,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
|
|
||||||
for (final JpaRolloutGroup rolloutGroup : rolloutGroups) {
|
for (final JpaRolloutGroup rolloutGroup : rolloutGroups) {
|
||||||
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
|
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
|
||||||
allStatesForRollout.get(rolloutGroup.getId()), (long)rolloutGroup.getTotalTargets(),
|
allStatesForRollout.get(rolloutGroup.getId()), (long) rolloutGroup.getTotalTargets(),
|
||||||
rolloutGroup.getRollout().getActionType());
|
rolloutGroup.getRollout().getActionType());
|
||||||
rolloutGroup.setTotalTargetCountStatus(totalTargetCountStatus);
|
rolloutGroup.setTotalTargetCountStatus(totalTargetCountStatus);
|
||||||
}
|
}
|
||||||
@@ -162,6 +131,49 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
return JpaManagementHelper.convertPage(rolloutGroups, pageable);
|
return JpaManagementHelper.convertPage(rolloutGroups, pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<TargetWithActionStatus> findAllTargetsOfRolloutGroupWithActionStatus(final Pageable pageRequest,
|
||||||
|
final long rolloutGroupId) {
|
||||||
|
|
||||||
|
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
|
||||||
|
|
||||||
|
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||||
|
final CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
|
||||||
|
final Root<RolloutTargetGroup> targetRoot = query.distinct(true).from(RolloutTargetGroup.class);
|
||||||
|
final Join<RolloutTargetGroup, JpaTarget> targetJoin = targetRoot.join(RolloutTargetGroup_.target);
|
||||||
|
final ListJoin<RolloutTargetGroup, JpaAction> actionJoin = targetRoot.join(RolloutTargetGroup_.actions,
|
||||||
|
JoinType.LEFT);
|
||||||
|
|
||||||
|
final CriteriaQuery<Object[]> multiselect = query
|
||||||
|
.multiselect(targetJoin, actionJoin.get(JpaAction_.status),
|
||||||
|
actionJoin.get(JpaAction_.lastActionStatusCode))
|
||||||
|
.where(getRolloutGroupTargetWithRolloutGroupJoinCondition(rolloutGroupId, cb, targetRoot))
|
||||||
|
.orderBy(getOrderBy(pageRequest, cb, targetJoin, actionJoin));
|
||||||
|
final List<TargetWithActionStatus> targetWithActionStatus = entityManager.createQuery(multiselect)
|
||||||
|
.setFirstResult((int) pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize()).getResultList()
|
||||||
|
.stream().map(this::getTargetWithActionStatusFromQuery).collect(Collectors.toList());
|
||||||
|
|
||||||
|
return new PageImpl<>(targetWithActionStatus, pageRequest, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<RolloutGroup> get(final long rolloutGroupId) {
|
||||||
|
return rolloutGroupRepository.findById(rolloutGroupId).map(RolloutGroup.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<RolloutGroup> findByRolloutAndRsql(final Pageable pageable, final long rolloutId,
|
||||||
|
final String rsqlParam) {
|
||||||
|
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
||||||
|
|
||||||
|
final List<Specification<JpaRolloutGroup>> specList = Arrays.asList(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, RolloutGroupFields.class, virtualPropertyReplacer,
|
||||||
|
database),
|
||||||
|
(root, query, cb) -> cb.equal(root.get(JpaRolloutGroup_.rollout).get(JpaRollout_.id), rolloutId));
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(rolloutGroupRepository, pageable, specList);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<RolloutGroup> findByRolloutAndRsqlWithDetailedStatus(final Pageable pageable, final long rolloutId,
|
public Page<RolloutGroup> findByRolloutAndRsqlWithDetailedStatus(final Pageable pageable, final long rolloutId,
|
||||||
final String rsqlParam) {
|
final String rsqlParam) {
|
||||||
@@ -189,6 +201,53 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
return JpaManagementHelper.convertPage(rolloutGroups, pageable);
|
return JpaManagementHelper.convertPage(rolloutGroups, pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<RolloutGroup> findByRollout(final Pageable pageable, final long rolloutId) {
|
||||||
|
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
||||||
|
|
||||||
|
return JpaManagementHelper.convertPage(rolloutGroupRepository.findByRolloutId(rolloutId, pageable), pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countByRollout(final long rolloutId) {
|
||||||
|
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
||||||
|
|
||||||
|
return rolloutGroupRepository.countByRolloutId(rolloutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Target> findTargetsOfRolloutGroup(final Pageable page, final long rolloutGroupId) {
|
||||||
|
final JpaRolloutGroup rolloutGroup = rolloutGroupRepository.findById(rolloutGroupId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutGroupId));
|
||||||
|
|
||||||
|
if (isRolloutStatusReady(rolloutGroup)) {
|
||||||
|
// in case of status ready the action has not been created yet and
|
||||||
|
// the relation information between target and rollout-group is
|
||||||
|
// stored in the #TargetRolloutGroup.
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, page,
|
||||||
|
Collections.singletonList(TargetSpecifications.isInRolloutGroup(rolloutGroupId)));
|
||||||
|
}
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, page,
|
||||||
|
Collections.singletonList(TargetSpecifications.isInActionRolloutGroup(rolloutGroupId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Target> findTargetsOfRolloutGroupByRsql(final Pageable pageable, final long rolloutGroupId,
|
||||||
|
final String rsqlParam) {
|
||||||
|
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
|
||||||
|
|
||||||
|
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, TargetFields.class, virtualPropertyReplacer, database),
|
||||||
|
(root, query, cb) -> {
|
||||||
|
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root
|
||||||
|
.join(JpaTarget_.rolloutTargetGroup);
|
||||||
|
return cb.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup).get(JpaRolloutGroup_.id),
|
||||||
|
rolloutGroupId);
|
||||||
|
});
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageable, specList);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<RolloutGroup> getWithDetailedStatus(final long rolloutGroupId) {
|
public Optional<RolloutGroup> getWithDetailedStatus(final long rolloutGroupId) {
|
||||||
final Optional<RolloutGroup> rolloutGroup = get(rolloutGroupId);
|
final Optional<RolloutGroup> rolloutGroup = get(rolloutGroupId);
|
||||||
@@ -214,6 +273,28 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTargetsOfRolloutsGroup(final long rolloutGroupId) {
|
||||||
|
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
|
||||||
|
|
||||||
|
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||||
|
final CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
|
||||||
|
final Root<RolloutTargetGroup> countQueryFrom = countQuery.from(RolloutTargetGroup.class);
|
||||||
|
countQuery.select(cb.count(countQueryFrom))
|
||||||
|
.where(getRolloutGroupTargetWithRolloutGroupJoinCondition(rolloutGroupId, cb, countQueryFrom));
|
||||||
|
return entityManager.createQuery(countQuery).getSingleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isRolloutStatusReady(final RolloutGroup rolloutGroup) {
|
||||||
|
return rolloutGroup != null && (RolloutStatus.READY == rolloutGroup.getRollout().getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void throwEntityNotFoundExceptionIfRolloutDoesNotExist(final Long rolloutId) {
|
||||||
|
if (!rolloutRepository.existsById(rolloutId)) {
|
||||||
|
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Map<Long, List<TotalTargetCountActionStatus>> getStatusCountItemForRolloutGroup(final List<Long> groupIds) {
|
private Map<Long, List<TotalTargetCountActionStatus>> getStatusCountItemForRolloutGroup(final List<Long> groupIds) {
|
||||||
final Map<Long, List<TotalTargetCountActionStatus>> fromCache = rolloutStatusCache
|
final Map<Long, List<TotalTargetCountActionStatus>> fromCache = rolloutStatusCache
|
||||||
.getRolloutGroupStatus(groupIds);
|
.getRolloutGroupStatus(groupIds);
|
||||||
@@ -235,68 +316,6 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
return fromCache;
|
return fromCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<Target> findTargetsOfRolloutGroupByRsql(final Pageable pageable, final long rolloutGroupId,
|
|
||||||
final String rsqlParam) {
|
|
||||||
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
|
|
||||||
|
|
||||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, TargetFields.class, virtualPropertyReplacer, database),
|
|
||||||
(root, query, cb) -> {
|
|
||||||
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root
|
|
||||||
.join(JpaTarget_.rolloutTargetGroup);
|
|
||||||
return cb.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup).get(JpaRolloutGroup_.id),
|
|
||||||
rolloutGroupId);
|
|
||||||
});
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageable, specList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<Target> findTargetsOfRolloutGroup(final Pageable page, final long rolloutGroupId) {
|
|
||||||
final JpaRolloutGroup rolloutGroup = rolloutGroupRepository.findById(rolloutGroupId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutGroupId));
|
|
||||||
|
|
||||||
if (isRolloutStatusReady(rolloutGroup)) {
|
|
||||||
// in case of status ready the action has not been created yet and
|
|
||||||
// the relation information between target and rollout-group is
|
|
||||||
// stored in the #TargetRolloutGroup.
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, page,
|
|
||||||
Collections.singletonList(TargetSpecifications.isInRolloutGroup(rolloutGroupId)));
|
|
||||||
}
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, page,
|
|
||||||
Collections.singletonList(TargetSpecifications.isInActionRolloutGroup(rolloutGroupId)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isRolloutStatusReady(final RolloutGroup rolloutGroup) {
|
|
||||||
return rolloutGroup != null && (RolloutStatus.READY == rolloutGroup.getRollout().getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<TargetWithActionStatus> findAllTargetsOfRolloutGroupWithActionStatus(final Pageable pageRequest,
|
|
||||||
final long rolloutGroupId) {
|
|
||||||
|
|
||||||
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
|
|
||||||
|
|
||||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
|
||||||
final CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
|
|
||||||
final Root<RolloutTargetGroup> targetRoot = query.distinct(true).from(RolloutTargetGroup.class);
|
|
||||||
final Join<RolloutTargetGroup, JpaTarget> targetJoin = targetRoot.join(RolloutTargetGroup_.target);
|
|
||||||
final ListJoin<RolloutTargetGroup, JpaAction> actionJoin = targetRoot.join(RolloutTargetGroup_.actions,
|
|
||||||
JoinType.LEFT);
|
|
||||||
|
|
||||||
final CriteriaQuery<Object[]> multiselect = query
|
|
||||||
.multiselect(targetJoin, actionJoin.get(JpaAction_.status),
|
|
||||||
actionJoin.get(JpaAction_.lastActionStatusCode))
|
|
||||||
.where(getRolloutGroupTargetWithRolloutGroupJoinCondition(rolloutGroupId, cb, targetRoot))
|
|
||||||
.orderBy(getOrderBy(pageRequest, cb, targetJoin, actionJoin));
|
|
||||||
final List<TargetWithActionStatus> targetWithActionStatus = entityManager.createQuery(multiselect)
|
|
||||||
.setFirstResult((int) pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize()).getResultList()
|
|
||||||
.stream().map(this::getTargetWithActionStatusFromQuery).collect(Collectors.toList());
|
|
||||||
|
|
||||||
return new PageImpl<>(targetWithActionStatus, pageRequest, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Predicate getRolloutGroupTargetWithRolloutGroupJoinCondition(final long rolloutGroupId,
|
private Predicate getRolloutGroupTargetWithRolloutGroupJoinCondition(final long rolloutGroupId,
|
||||||
final CriteriaBuilder cb, final Root<RolloutTargetGroup> targetRoot) {
|
final CriteriaBuilder cb, final Root<RolloutTargetGroup> targetRoot) {
|
||||||
return cb.equal(targetRoot.get(RolloutTargetGroup_.rolloutGroup).get(JpaRolloutGroup_.id), //
|
return cb.equal(targetRoot.get(RolloutTargetGroup_.rolloutGroup).get(JpaRolloutGroup_.id), //
|
||||||
@@ -327,29 +346,10 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
|||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countTargetsOfRolloutsGroup(final long rolloutGroupId) {
|
|
||||||
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
|
|
||||||
|
|
||||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
|
||||||
final CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
|
|
||||||
final Root<RolloutTargetGroup> countQueryFrom = countQuery.from(RolloutTargetGroup.class);
|
|
||||||
countQuery.select(cb.count(countQueryFrom))
|
|
||||||
.where(getRolloutGroupTargetWithRolloutGroupJoinCondition(rolloutGroupId, cb, countQueryFrom));
|
|
||||||
return entityManager.createQuery(countQuery).getSingleResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void throwExceptionIfRolloutGroupDoesNotExist(final Long rolloutGroupId) {
|
private void throwExceptionIfRolloutGroupDoesNotExist(final Long rolloutGroupId) {
|
||||||
if (!rolloutGroupRepository.existsById(rolloutGroupId)) {
|
if (!rolloutGroupRepository.existsById(rolloutGroupId)) {
|
||||||
throw new EntityNotFoundException(RolloutGroup.class, rolloutGroupId);
|
throw new EntityNotFoundException(RolloutGroup.class, rolloutGroupId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countByRollout(final long rolloutId) {
|
|
||||||
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
|
|
||||||
|
|
||||||
return rolloutGroupRepository.countByRolloutId(rolloutId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ import java.util.stream.Collectors;
|
|||||||
import jakarta.validation.ConstraintDeclarationException;
|
import jakarta.validation.ConstraintDeclarationException;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.ValidationException;
|
import jakarta.validation.ValidationException;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.eclipse.hawkbit.ContextAware;
|
||||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||||
@@ -37,7 +38,6 @@ import org.eclipse.hawkbit.repository.RolloutManagement;
|
|||||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||||
import org.eclipse.hawkbit.ContextAware;
|
|
||||||
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
|
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
|
||||||
import org.eclipse.hawkbit.repository.builder.GenericRolloutUpdate;
|
import org.eclipse.hawkbit.repository.builder.GenericRolloutUpdate;
|
||||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||||
@@ -110,31 +110,6 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
private static final List<RolloutStatus> ROLLOUT_STATUS_STOPPABLE = Arrays.asList(RolloutStatus.RUNNING,
|
private static final List<RolloutStatus> ROLLOUT_STATUS_STOPPABLE = Arrays.asList(RolloutStatus.RUNNING,
|
||||||
RolloutStatus.CREATING, RolloutStatus.PAUSED, RolloutStatus.READY, RolloutStatus.STARTING,
|
RolloutStatus.CREATING, RolloutStatus.PAUSED, RolloutStatus.READY, RolloutStatus.STARTING,
|
||||||
RolloutStatus.WAITING_FOR_APPROVAL, RolloutStatus.APPROVAL_DENIED);
|
RolloutStatus.WAITING_FOR_APPROVAL, RolloutStatus.APPROVAL_DENIED);
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RepositoryProperties repositoryProperties;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RolloutRepository rolloutRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RolloutGroupRepository rolloutGroupRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ActionRepository actionRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AfterTransactionCommitExecutor afterCommit;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private QuotaManagement quotaManagement;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RolloutStatusCache rolloutStatusCache;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private StartNextGroupRolloutGroupSuccessAction startNextRolloutGroupAction;
|
|
||||||
|
|
||||||
private final TargetManagement targetManagement;
|
private final TargetManagement targetManagement;
|
||||||
private final DistributionSetManagement distributionSetManagement;
|
private final DistributionSetManagement distributionSetManagement;
|
||||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||||
@@ -144,6 +119,22 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
private final EventPublisherHolder eventPublisherHolder;
|
private final EventPublisherHolder eventPublisherHolder;
|
||||||
private final ContextAware contextAware;
|
private final ContextAware contextAware;
|
||||||
private final Database database;
|
private final Database database;
|
||||||
|
@Autowired
|
||||||
|
private RepositoryProperties repositoryProperties;
|
||||||
|
@Autowired
|
||||||
|
private RolloutRepository rolloutRepository;
|
||||||
|
@Autowired
|
||||||
|
private RolloutGroupRepository rolloutGroupRepository;
|
||||||
|
@Autowired
|
||||||
|
private ActionRepository actionRepository;
|
||||||
|
@Autowired
|
||||||
|
private AfterTransactionCommitExecutor afterCommit;
|
||||||
|
@Autowired
|
||||||
|
private QuotaManagement quotaManagement;
|
||||||
|
@Autowired
|
||||||
|
private RolloutStatusCache rolloutStatusCache;
|
||||||
|
@Autowired
|
||||||
|
private StartNextGroupRolloutGroupSuccessAction startNextRolloutGroupAction;
|
||||||
|
|
||||||
public JpaRolloutManagement(final TargetManagement targetManagement,
|
public JpaRolloutManagement(final TargetManagement targetManagement,
|
||||||
final DistributionSetManagement distributionSetManagement, final EventPublisherHolder eventPublisherHolder,
|
final DistributionSetManagement distributionSetManagement, final EventPublisherHolder eventPublisherHolder,
|
||||||
@@ -163,34 +154,29 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
this.contextAware = contextAware;
|
this.contextAware = contextAware;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static String createRolloutLockKey(final String tenant) {
|
||||||
public Page<Rollout> findAll(final Pageable pageable, final boolean deleted) {
|
return tenant + "-rollout";
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable, Collections
|
}
|
||||||
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
|
|
||||||
|
public void publishRolloutGroupCreatedEventAfterCommit(final RolloutGroup group, final Rollout rollout) {
|
||||||
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
||||||
|
new RolloutGroupCreatedEvent(group, rollout.getId(), eventPublisherHolder.getApplicationId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<Rollout> findByRsql(final Pageable pageable, final String rsqlParam, final boolean deleted) {
|
public long count() {
|
||||||
final List<Specification<JpaRollout>> specList = new ArrayList<>(2);
|
return rolloutRepository.count(
|
||||||
specList.add(
|
RolloutSpecification.isDeletedWithDistributionSet(false, Sort.by(Direction.DESC, JpaRollout_.ID)));
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, RolloutFields.class, virtualPropertyReplacer, database));
|
|
||||||
specList.add(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort()));
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable, specList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Rollout> get(final long rolloutId) {
|
public long countByFilters(final String searchText) {
|
||||||
return rolloutRepository.findById(rolloutId).map(Rollout.class::cast);
|
return rolloutRepository.count(RolloutSpecification.likeName(searchText, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
public long countByDistributionSetIdAndRolloutIsStoppable(final long setId) {
|
||||||
@Retryable(include = {
|
return rolloutRepository.countByDistributionSetIdAndStatusIn(setId, ROLLOUT_STATUS_STOPPABLE);
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Rollout create(@NotNull @Valid RolloutCreate create, int amountGroup, boolean confirmationRequired,
|
|
||||||
@NotNull RolloutGroupConditions conditions) {
|
|
||||||
return create(create, amountGroup, confirmationRequired, conditions, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -204,7 +190,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
} else if (amountGroup == 0) {
|
} else if (amountGroup == 0) {
|
||||||
if (dynamicRolloutGroupTemplate == null) {
|
if (dynamicRolloutGroupTemplate == null) {
|
||||||
throw new ValidationException(
|
throw new ValidationException(
|
||||||
"When amount of groups is 0, the rollouts shall be dynamic and a dynamic group template must be provided");
|
"When amount of groups is 0, the rollouts shall be dynamic and a dynamic group template must be provided");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RolloutHelper.verifyRolloutGroupAmount(amountGroup, quotaManagement);
|
RolloutHelper.verifyRolloutGroupAmount(amountGroup, quotaManagement);
|
||||||
@@ -219,6 +205,15 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
return createRolloutGroups(amountGroup, conditions, savedRollout, confirmationRequired, dynamicRolloutGroupTemplate);
|
return createRolloutGroups(amountGroup, conditions, savedRollout, confirmationRequired, dynamicRolloutGroupTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public Rollout create(@NotNull @Valid RolloutCreate create, int amountGroup, boolean confirmationRequired,
|
||||||
|
@NotNull RolloutGroupConditions conditions) {
|
||||||
|
return create(create, amountGroup, confirmationRequired, conditions, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -234,6 +229,314 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
return createRolloutGroups(groups, conditions, savedRollout);
|
return createRolloutGroups(groups, conditions, savedRollout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async
|
||||||
|
public ListenableFuture<RolloutGroupsValidation> validateTargetsInGroups(final List<RolloutGroupCreate> groups,
|
||||||
|
final String targetFilter, final Long createdAt, final Long dsTypeId) {
|
||||||
|
|
||||||
|
final TargetCount targets = calculateTargets(targetFilter, createdAt, dsTypeId);
|
||||||
|
long totalTargets = targets.total();
|
||||||
|
final String baseFilter = targets.filter();
|
||||||
|
|
||||||
|
if (totalTargets == 0) {
|
||||||
|
throw new ConstraintDeclarationException("Rollout target filter does not match any targets");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AsyncResult<>(
|
||||||
|
validateTargetsInGroups(groups.stream().map(RolloutGroupCreate::build).collect(Collectors.toList()),
|
||||||
|
baseFilter, totalTargets, dsTypeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Rollout> findAll(final Pageable pageable, final boolean deleted) {
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable, Collections
|
||||||
|
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<Rollout> findAllWithDetailedStatus(final Pageable pageable, final boolean deleted) {
|
||||||
|
final Slice<Rollout> rollouts = JpaManagementHelper.findAllWithoutCountBySpec(rolloutRepository, pageable,
|
||||||
|
Collections
|
||||||
|
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
|
||||||
|
setRolloutStatusDetails(rollouts);
|
||||||
|
return rollouts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Rollout> findByRsql(final Pageable pageable, final String rsqlParam, final boolean deleted) {
|
||||||
|
final List<Specification<JpaRollout>> specList = new ArrayList<>(2);
|
||||||
|
specList.add(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, RolloutFields.class, virtualPropertyReplacer, database));
|
||||||
|
specList.add(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort()));
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable, specList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<Rollout> findByFiltersWithDetailedStatus(final Pageable pageable, final String searchText,
|
||||||
|
final boolean deleted) {
|
||||||
|
final Slice<Rollout> findAll = JpaManagementHelper.findAllWithoutCountBySpec(rolloutRepository, pageable,
|
||||||
|
Collections.singletonList(RolloutSpecification.likeName(searchText, deleted)));
|
||||||
|
setRolloutStatusDetails(findAll);
|
||||||
|
return findAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> findActiveRollouts() {
|
||||||
|
return rolloutRepository.findByStatusIn(ACTIVE_ROLLOUTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Rollout> get(final long rolloutId) {
|
||||||
|
return rolloutRepository.findById(rolloutId).map(Rollout.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Rollout> getByName(final String rolloutName) {
|
||||||
|
return rolloutRepository.findByName(rolloutName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Rollout> getWithDetailedStatus(final long rolloutId) {
|
||||||
|
final Optional<Rollout> rollout = get(rolloutId);
|
||||||
|
|
||||||
|
if (!rollout.isPresent()) {
|
||||||
|
return rollout;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TotalTargetCountActionStatus> rolloutStatusCountItems = rolloutStatusCache.getRolloutStatus(rolloutId);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(rolloutStatusCountItems)) {
|
||||||
|
rolloutStatusCountItems = actionRepository.getStatusCountByRolloutId(rolloutId);
|
||||||
|
rolloutStatusCache.putRolloutStatus(rolloutId, rolloutStatusCountItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(rolloutStatusCountItems,
|
||||||
|
rollout.get().getTotalTargets(), rollout.get().getActionType());
|
||||||
|
((JpaRollout) rollout.get()).setTotalTargetCountStatus(totalTargetCountStatus);
|
||||||
|
return rollout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists(final long rolloutId) {
|
||||||
|
return rolloutRepository.existsById(rolloutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void pauseRollout(final long rolloutId) {
|
||||||
|
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
||||||
|
if (RolloutStatus.RUNNING != rollout.getStatus()) {
|
||||||
|
throw new RolloutIllegalStateException("Rollout can only be paused in state running but current state is "
|
||||||
|
+ rollout.getStatus().name().toLowerCase());
|
||||||
|
}
|
||||||
|
// setting the complete rollout only in paused state. This is sufficient
|
||||||
|
// due the currently running groups will be completed and new groups are
|
||||||
|
// not started until rollout goes back to running state again. The
|
||||||
|
// periodically check for running rollouts will skip rollouts in pause
|
||||||
|
// state.
|
||||||
|
rollout.setStatus(RolloutStatus.PAUSED);
|
||||||
|
rolloutRepository.save(rollout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void resumeRollout(final long rolloutId) {
|
||||||
|
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
||||||
|
if (RolloutStatus.PAUSED != rollout.getStatus()) {
|
||||||
|
throw new RolloutIllegalStateException("Rollout can only be resumed in state paused but current state is "
|
||||||
|
+ rollout.getStatus().name().toLowerCase());
|
||||||
|
}
|
||||||
|
rollout.setStatus(RolloutStatus.RUNNING);
|
||||||
|
rolloutRepository.save(rollout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public Rollout approveOrDeny(final long rolloutId, final Rollout.ApprovalDecision decision) {
|
||||||
|
return this.approveOrDeny(rolloutId, decision, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public Rollout approveOrDeny(final long rolloutId, final Rollout.ApprovalDecision decision, final String remark) {
|
||||||
|
log.debug("approveOrDeny rollout called for rollout {} with decision {}", rolloutId, decision);
|
||||||
|
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
||||||
|
RolloutHelper.verifyRolloutInStatus(rollout, RolloutStatus.WAITING_FOR_APPROVAL);
|
||||||
|
switch (decision) {
|
||||||
|
case APPROVED:
|
||||||
|
rollout.setStatus(RolloutStatus.READY);
|
||||||
|
break;
|
||||||
|
case DENIED:
|
||||||
|
rollout.setStatus(RolloutStatus.APPROVAL_DENIED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown approval decision: " + decision);
|
||||||
|
}
|
||||||
|
rollout.setApprovalDecidedBy(rolloutApprovalStrategy.getApprovalUser(rollout));
|
||||||
|
if (remark != null) {
|
||||||
|
rollout.setApprovalRemark(remark);
|
||||||
|
}
|
||||||
|
return rolloutRepository.save(rollout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public Rollout start(final long rolloutId) {
|
||||||
|
log.debug("startRollout called for rollout {}", rolloutId);
|
||||||
|
|
||||||
|
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
||||||
|
RolloutHelper.checkIfRolloutCanStarted(rollout, rollout);
|
||||||
|
rollout.setStatus(RolloutStatus.STARTING);
|
||||||
|
rollout.setLastCheck(0);
|
||||||
|
return rolloutRepository.save(rollout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public Rollout update(final RolloutUpdate u) {
|
||||||
|
final GenericRolloutUpdate update = (GenericRolloutUpdate) u;
|
||||||
|
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(update.getId());
|
||||||
|
|
||||||
|
checkIfDeleted(update.getId(), rollout.getStatus());
|
||||||
|
|
||||||
|
update.getName().ifPresent(rollout::setName);
|
||||||
|
update.getDescription().ifPresent(rollout::setDescription);
|
||||||
|
return rolloutRepository.save(rollout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void delete(final long rolloutId) {
|
||||||
|
final JpaRollout jpaRollout = rolloutRepository.findById(rolloutId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||||
|
|
||||||
|
if (jpaRollout == null) {
|
||||||
|
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RolloutStatus.DELETING == jpaRollout.getStatus()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpaRollout.setStatus(RolloutStatus.DELETING);
|
||||||
|
rolloutRepository.save(jpaRollout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void cancelRolloutsForDistributionSet(final DistributionSet set) {
|
||||||
|
// stop all rollouts for this distribution set
|
||||||
|
rolloutRepository.findByDistributionSetAndStatusIn(set, ROLLOUT_STATUS_STOPPABLE).forEach(rollout -> {
|
||||||
|
final JpaRollout jpaRollout = (JpaRollout) rollout;
|
||||||
|
jpaRollout.setStatus(RolloutStatus.STOPPING);
|
||||||
|
rolloutRepository.save(jpaRollout);
|
||||||
|
log.debug("Rollout {} stopped", jpaRollout.getId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void triggerNextGroup(final long rolloutId) {
|
||||||
|
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
||||||
|
if (RolloutStatus.RUNNING != rollout.getStatus()) {
|
||||||
|
throw new RolloutIllegalStateException("Rollout is not in running state");
|
||||||
|
}
|
||||||
|
final List<RolloutGroup> groups = rollout.getRolloutGroups();
|
||||||
|
|
||||||
|
final boolean isNextGroupTriggerable = groups.stream()
|
||||||
|
.anyMatch(g -> RolloutGroupStatus.SCHEDULED.equals(g.getStatus()));
|
||||||
|
|
||||||
|
if (!isNextGroupTriggerable) {
|
||||||
|
throw new RolloutIllegalStateException("Rollout does not have any groups left to be triggered");
|
||||||
|
}
|
||||||
|
|
||||||
|
final RolloutGroup latestRunning = groups.stream()
|
||||||
|
.sorted(Comparator.comparingLong(RolloutGroup::getId).reversed())
|
||||||
|
.filter(g -> RolloutGroupStatus.RUNNING.equals(g.getStatus()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new RolloutIllegalStateException("No group is running"));
|
||||||
|
|
||||||
|
startNextRolloutGroupAction.exec(rollout, latestRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRolloutStatusDetails(final Slice<Rollout> rollouts) {
|
||||||
|
final List<Long> rolloutIds = rollouts.getContent().stream().map(Rollout::getId).collect(Collectors.toList());
|
||||||
|
final Map<Long, List<TotalTargetCountActionStatus>> allStatesForRollout = getStatusCountItemForRollout(
|
||||||
|
rolloutIds);
|
||||||
|
|
||||||
|
if (allStatesForRollout != null) {
|
||||||
|
rollouts.forEach(rollout -> {
|
||||||
|
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
|
||||||
|
allStatesForRollout.get(rollout.getId()), rollout.getTotalTargets(), rollout.getActionType());
|
||||||
|
((JpaRollout) rollout).setTotalTargetCountStatus(totalTargetCountStatus);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case the given group is missing conditions or actions, they will be set
|
||||||
|
* from the supplied default conditions.
|
||||||
|
*
|
||||||
|
* @param create group to check
|
||||||
|
* @param conditions default conditions and actions
|
||||||
|
*/
|
||||||
|
private static JpaRolloutGroup prepareRolloutGroupWithDefaultConditions(final RolloutGroupCreate create,
|
||||||
|
final RolloutGroupConditions conditions) {
|
||||||
|
final JpaRolloutGroup group = ((JpaRolloutGroupCreate) create).build();
|
||||||
|
|
||||||
|
if (group.getSuccessCondition() == null) {
|
||||||
|
group.setSuccessCondition(conditions.getSuccessCondition());
|
||||||
|
}
|
||||||
|
if (group.getSuccessConditionExp() == null) {
|
||||||
|
group.setSuccessConditionExp(conditions.getSuccessConditionExp());
|
||||||
|
}
|
||||||
|
if (group.getSuccessAction() == null) {
|
||||||
|
group.setSuccessAction(conditions.getSuccessAction());
|
||||||
|
}
|
||||||
|
if (group.getSuccessActionExp() == null) {
|
||||||
|
group.setSuccessActionExp(conditions.getSuccessActionExp());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group.getErrorCondition() == null) {
|
||||||
|
group.setErrorCondition(conditions.getErrorCondition());
|
||||||
|
}
|
||||||
|
if (group.getErrorConditionExp() == null) {
|
||||||
|
group.setErrorConditionExp(conditions.getErrorConditionExp());
|
||||||
|
}
|
||||||
|
if (group.getErrorAction() == null) {
|
||||||
|
group.setErrorAction(conditions.getErrorAction());
|
||||||
|
}
|
||||||
|
if (group.getErrorActionExp() == null) {
|
||||||
|
group.setErrorActionExp(conditions.getErrorActionExp());
|
||||||
|
}
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkIfDeleted(final Long rolloutId, final RolloutStatus status) {
|
||||||
|
if (RolloutStatus.DELETING == status || RolloutStatus.DELETED == status) {
|
||||||
|
throw new EntityReadOnlyException("Rollout " + rolloutId + " is soft deleted and cannot be changed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private JpaRollout createRollout(final JpaRollout rollout, final boolean pureDynamic) {
|
private JpaRollout createRollout(final JpaRollout rollout, final boolean pureDynamic) {
|
||||||
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(rollout);
|
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(rollout);
|
||||||
final JpaDistributionSet distributionSet = (JpaDistributionSet) rollout.getDistributionSet();
|
final JpaDistributionSet distributionSet = (JpaDistributionSet) rollout.getDistributionSet();
|
||||||
@@ -259,7 +562,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
rollout.setTotalTargets(totalTargets);
|
rollout.setTotalTargets(totalTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((JpaDistributionSetManagement)distributionSetManagement).isImplicitLockApplicable(distributionSet)) {
|
if (((JpaDistributionSetManagement) distributionSetManagement).isImplicitLockApplicable(distributionSet)) {
|
||||||
distributionSetManagement.lock(distributionSet.getId());
|
distributionSetManagement.lock(distributionSet.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,253 +694,11 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
return rolloutRepository.save(savedRollout);
|
return rolloutRepository.save(savedRollout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* In case the given group is missing conditions or actions, they will be set
|
|
||||||
* from the supplied default conditions.
|
|
||||||
*
|
|
||||||
* @param create
|
|
||||||
* group to check
|
|
||||||
* @param conditions
|
|
||||||
* default conditions and actions
|
|
||||||
*/
|
|
||||||
private static JpaRolloutGroup prepareRolloutGroupWithDefaultConditions(final RolloutGroupCreate create,
|
|
||||||
final RolloutGroupConditions conditions) {
|
|
||||||
final JpaRolloutGroup group = ((JpaRolloutGroupCreate) create).build();
|
|
||||||
|
|
||||||
if (group.getSuccessCondition() == null) {
|
|
||||||
group.setSuccessCondition(conditions.getSuccessCondition());
|
|
||||||
}
|
|
||||||
if (group.getSuccessConditionExp() == null) {
|
|
||||||
group.setSuccessConditionExp(conditions.getSuccessConditionExp());
|
|
||||||
}
|
|
||||||
if (group.getSuccessAction() == null) {
|
|
||||||
group.setSuccessAction(conditions.getSuccessAction());
|
|
||||||
}
|
|
||||||
if (group.getSuccessActionExp() == null) {
|
|
||||||
group.setSuccessActionExp(conditions.getSuccessActionExp());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group.getErrorCondition() == null) {
|
|
||||||
group.setErrorCondition(conditions.getErrorCondition());
|
|
||||||
}
|
|
||||||
if (group.getErrorConditionExp() == null) {
|
|
||||||
group.setErrorConditionExp(conditions.getErrorConditionExp());
|
|
||||||
}
|
|
||||||
if (group.getErrorAction() == null) {
|
|
||||||
group.setErrorAction(conditions.getErrorAction());
|
|
||||||
}
|
|
||||||
if (group.getErrorActionExp() == null) {
|
|
||||||
group.setErrorActionExp(conditions.getErrorActionExp());
|
|
||||||
}
|
|
||||||
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void publishRolloutGroupCreatedEventAfterCommit(final RolloutGroup group, final Rollout rollout) {
|
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
|
||||||
new RolloutGroupCreatedEvent(group, rollout.getId(), eventPublisherHolder.getApplicationId())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Rollout approveOrDeny(final long rolloutId, final Rollout.ApprovalDecision decision) {
|
|
||||||
return this.approveOrDeny(rolloutId, decision, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Rollout approveOrDeny(final long rolloutId, final Rollout.ApprovalDecision decision, final String remark) {
|
|
||||||
log.debug("approveOrDeny rollout called for rollout {} with decision {}", rolloutId, decision);
|
|
||||||
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
|
||||||
RolloutHelper.verifyRolloutInStatus(rollout, RolloutStatus.WAITING_FOR_APPROVAL);
|
|
||||||
switch (decision) {
|
|
||||||
case APPROVED:
|
|
||||||
rollout.setStatus(RolloutStatus.READY);
|
|
||||||
break;
|
|
||||||
case DENIED:
|
|
||||||
rollout.setStatus(RolloutStatus.APPROVAL_DENIED);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown approval decision: " + decision);
|
|
||||||
}
|
|
||||||
rollout.setApprovalDecidedBy(rolloutApprovalStrategy.getApprovalUser(rollout));
|
|
||||||
if (remark != null) {
|
|
||||||
rollout.setApprovalRemark(remark);
|
|
||||||
}
|
|
||||||
return rolloutRepository.save(rollout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Rollout start(final long rolloutId) {
|
|
||||||
log.debug("startRollout called for rollout {}", rolloutId);
|
|
||||||
|
|
||||||
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
|
||||||
RolloutHelper.checkIfRolloutCanStarted(rollout, rollout);
|
|
||||||
rollout.setStatus(RolloutStatus.STARTING);
|
|
||||||
rollout.setLastCheck(0);
|
|
||||||
return rolloutRepository.save(rollout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void pauseRollout(final long rolloutId) {
|
|
||||||
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
|
||||||
if (RolloutStatus.RUNNING != rollout.getStatus()) {
|
|
||||||
throw new RolloutIllegalStateException("Rollout can only be paused in state running but current state is "
|
|
||||||
+ rollout.getStatus().name().toLowerCase());
|
|
||||||
}
|
|
||||||
// setting the complete rollout only in paused state. This is sufficient
|
|
||||||
// due the currently running groups will be completed and new groups are
|
|
||||||
// not started until rollout goes back to running state again. The
|
|
||||||
// periodically check for running rollouts will skip rollouts in pause
|
|
||||||
// state.
|
|
||||||
rollout.setStatus(RolloutStatus.PAUSED);
|
|
||||||
rolloutRepository.save(rollout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void resumeRollout(final long rolloutId) {
|
|
||||||
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
|
||||||
if (RolloutStatus.PAUSED != rollout.getStatus()) {
|
|
||||||
throw new RolloutIllegalStateException("Rollout can only be resumed in state paused but current state is "
|
|
||||||
+ rollout.getStatus().name().toLowerCase());
|
|
||||||
}
|
|
||||||
rollout.setStatus(RolloutStatus.RUNNING);
|
|
||||||
rolloutRepository.save(rollout);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String createRolloutLockKey(final String tenant) {
|
|
||||||
return tenant + "-rollout";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void delete(final long rolloutId) {
|
|
||||||
final JpaRollout jpaRollout = rolloutRepository.findById(rolloutId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
|
||||||
|
|
||||||
if (jpaRollout == null) {
|
|
||||||
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RolloutStatus.DELETING == jpaRollout.getStatus()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
jpaRollout.setStatus(RolloutStatus.DELETING);
|
|
||||||
rolloutRepository.save(jpaRollout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count() {
|
|
||||||
return rolloutRepository.count(
|
|
||||||
RolloutSpecification.isDeletedWithDistributionSet(false, Sort.by(Direction.DESC, JpaRollout_.ID)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countByFilters(final String searchText) {
|
|
||||||
return rolloutRepository.count(RolloutSpecification.likeName(searchText, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countByDistributionSetIdAndRolloutIsStoppable(final long setId) {
|
|
||||||
return rolloutRepository.countByDistributionSetIdAndStatusIn(setId, ROLLOUT_STATUS_STOPPABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<Rollout> findByFiltersWithDetailedStatus(final Pageable pageable, final String searchText,
|
|
||||||
final boolean deleted) {
|
|
||||||
final Slice<Rollout> findAll = JpaManagementHelper.findAllWithoutCountBySpec(rolloutRepository, pageable,
|
|
||||||
Collections.singletonList(RolloutSpecification.likeName(searchText, deleted)));
|
|
||||||
setRolloutStatusDetails(findAll);
|
|
||||||
return findAll;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Long> findActiveRollouts() {
|
|
||||||
return rolloutRepository.findByStatusIn(ACTIVE_ROLLOUTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Rollout> getByName(final String rolloutName) {
|
|
||||||
return rolloutRepository.findByName(rolloutName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public Rollout update(final RolloutUpdate u) {
|
|
||||||
final GenericRolloutUpdate update = (GenericRolloutUpdate) u;
|
|
||||||
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(update.getId());
|
|
||||||
|
|
||||||
checkIfDeleted(update.getId(), rollout.getStatus());
|
|
||||||
|
|
||||||
update.getName().ifPresent(rollout::setName);
|
|
||||||
update.getDescription().ifPresent(rollout::setDescription);
|
|
||||||
return rolloutRepository.save(rollout);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkIfDeleted(final Long rolloutId, final RolloutStatus status) {
|
|
||||||
if (RolloutStatus.DELETING == status || RolloutStatus.DELETED == status) {
|
|
||||||
throw new EntityReadOnlyException("Rollout " + rolloutId + " is soft deleted and cannot be changed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JpaRollout getRolloutOrThrowExceptionIfNotFound(final Long rolloutId) {
|
private JpaRollout getRolloutOrThrowExceptionIfNotFound(final Long rolloutId) {
|
||||||
return rolloutRepository.findById(rolloutId)
|
return rolloutRepository.findById(rolloutId)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<Rollout> findAllWithDetailedStatus(final Pageable pageable, final boolean deleted) {
|
|
||||||
final Slice<Rollout> rollouts = JpaManagementHelper.findAllWithoutCountBySpec(rolloutRepository, pageable,
|
|
||||||
Collections
|
|
||||||
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
|
|
||||||
setRolloutStatusDetails(rollouts);
|
|
||||||
return rollouts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Rollout> getWithDetailedStatus(final long rolloutId) {
|
|
||||||
final Optional<Rollout> rollout = get(rolloutId);
|
|
||||||
|
|
||||||
if (!rollout.isPresent()) {
|
|
||||||
return rollout;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TotalTargetCountActionStatus> rolloutStatusCountItems = rolloutStatusCache.getRolloutStatus(rolloutId);
|
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(rolloutStatusCountItems)) {
|
|
||||||
rolloutStatusCountItems = actionRepository.getStatusCountByRolloutId(rolloutId);
|
|
||||||
rolloutStatusCache.putRolloutStatus(rolloutId, rolloutStatusCountItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(rolloutStatusCountItems,
|
|
||||||
rollout.get().getTotalTargets(), rollout.get().getActionType());
|
|
||||||
((JpaRollout) rollout.get()).setTotalTargetCountStatus(totalTargetCountStatus);
|
|
||||||
return rollout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean exists(final long rolloutId) {
|
|
||||||
return rolloutRepository.existsById(rolloutId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Long, List<TotalTargetCountActionStatus>> getStatusCountItemForRollout(final List<Long> rollouts) {
|
private Map<Long, List<TotalTargetCountActionStatus>> getStatusCountItemForRollout(final List<Long> rollouts) {
|
||||||
if (rollouts.isEmpty()) {
|
if (rollouts.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -662,60 +723,32 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
return fromCache;
|
return fromCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRolloutStatusDetails(final Slice<Rollout> rollouts) {
|
|
||||||
final List<Long> rolloutIds = rollouts.getContent().stream().map(Rollout::getId).collect(Collectors.toList());
|
|
||||||
final Map<Long, List<TotalTargetCountActionStatus>> allStatesForRollout = getStatusCountItemForRollout(
|
|
||||||
rolloutIds);
|
|
||||||
|
|
||||||
if (allStatesForRollout != null) {
|
|
||||||
rollouts.forEach(rollout -> {
|
|
||||||
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
|
|
||||||
allStatesForRollout.get(rollout.getId()), rollout.getTotalTargets(), rollout.getActionType());
|
|
||||||
((JpaRollout) rollout).setTotalTargetCountStatus(totalTargetCountStatus);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enforces the quota defining the maximum number of {@link Target}s per
|
* Enforces the quota defining the maximum number of {@link Target}s per
|
||||||
* {@link RolloutGroup}.
|
* {@link RolloutGroup}.
|
||||||
*
|
*
|
||||||
* @param requested
|
* @param requested number of targets to check
|
||||||
* number of targets to check
|
|
||||||
*/
|
*/
|
||||||
private void assertTargetsPerRolloutGroupQuota(final long requested) {
|
private void assertTargetsPerRolloutGroupQuota(final long requested) {
|
||||||
final int quota = quotaManagement.getMaxTargetsPerRolloutGroup();
|
final int quota = quotaManagement.getMaxTargetsPerRolloutGroup();
|
||||||
QuotaHelper.assertAssignmentQuota(requested, quota, Target.class, RolloutGroup.class);
|
QuotaHelper.assertAssignmentQuota(requested, quota, Target.class, RolloutGroup.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void cancelRolloutsForDistributionSet(final DistributionSet set) {
|
|
||||||
// stop all rollouts for this distribution set
|
|
||||||
rolloutRepository.findByDistributionSetAndStatusIn(set, ROLLOUT_STATUS_STOPPABLE).forEach(rollout -> {
|
|
||||||
final JpaRollout jpaRollout = (JpaRollout) rollout;
|
|
||||||
jpaRollout.setStatus(RolloutStatus.STOPPING);
|
|
||||||
rolloutRepository.save(jpaRollout);
|
|
||||||
log.debug("Rollout {} stopped", jpaRollout.getId());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private RolloutGroupsValidation validateTargetsInGroups(final List<RolloutGroup> groups, final String baseFilter,
|
private RolloutGroupsValidation validateTargetsInGroups(final List<RolloutGroup> groups, final String baseFilter,
|
||||||
final long totalTargets, final Long dsTypeId) {
|
final long totalTargets, final Long dsTypeId) {
|
||||||
final List<Long> groupTargetCounts = new ArrayList<>(groups.size());
|
final List<Long> groupTargetCounts = new ArrayList<>(groups.size());
|
||||||
Map<String, Long> targetFilterCounts;
|
Map<String, Long> targetFilterCounts;
|
||||||
if (!RolloutHelper.isRolloutRetried(baseFilter)) {
|
if (!RolloutHelper.isRolloutRetried(baseFilter)) {
|
||||||
targetFilterCounts = groups.stream()
|
targetFilterCounts = groups.stream()
|
||||||
.map(group -> RolloutHelper.getGroupTargetFilter(baseFilter, group)).distinct()
|
.map(group -> RolloutHelper.getGroupTargetFilter(baseFilter, group)).distinct()
|
||||||
.collect(Collectors.toMap(Function.identity(),
|
.collect(Collectors.toMap(Function.identity(),
|
||||||
groupTargetFilter -> targetManagement.countByRsqlAndCompatible(groupTargetFilter, dsTypeId)));
|
groupTargetFilter -> targetManagement.countByRsqlAndCompatible(groupTargetFilter, dsTypeId)));
|
||||||
} else {
|
} else {
|
||||||
targetFilterCounts = groups.stream()
|
targetFilterCounts = groups.stream()
|
||||||
.map(group -> RolloutHelper.getGroupTargetFilter(baseFilter, group)).distinct()
|
.map(group -> RolloutHelper.getGroupTargetFilter(baseFilter, group)).distinct()
|
||||||
.collect(Collectors.toMap(Function.identity(),
|
.collect(Collectors.toMap(Function.identity(),
|
||||||
groupTargetFilter -> targetManagement.countByFailedInRollout(
|
groupTargetFilter -> targetManagement.countByFailedInRollout(
|
||||||
RolloutHelper.getIdFromRetriedTargetFilter(baseFilter), dsTypeId)));
|
RolloutHelper.getIdFromRetriedTargetFilter(baseFilter), dsTypeId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
long unusedTargetsCount = 0;
|
long unusedTargetsCount = 0;
|
||||||
@@ -786,51 +819,6 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
return totalTargets - validation.getTargetsInGroups();
|
return totalTargets - validation.getTargetsInGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Async
|
|
||||||
public ListenableFuture<RolloutGroupsValidation> validateTargetsInGroups(final List<RolloutGroupCreate> groups,
|
|
||||||
final String targetFilter, final Long createdAt, final Long dsTypeId) {
|
|
||||||
|
|
||||||
final TargetCount targets = calculateTargets(targetFilter, createdAt, dsTypeId);
|
|
||||||
long totalTargets = targets.total();
|
|
||||||
final String baseFilter = targets.filter();
|
|
||||||
|
|
||||||
if (totalTargets == 0) {
|
|
||||||
throw new ConstraintDeclarationException("Rollout target filter does not match any targets");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AsyncResult<>(
|
|
||||||
validateTargetsInGroups(groups.stream().map(RolloutGroupCreate::build).collect(Collectors.toList()),
|
|
||||||
baseFilter, totalTargets, dsTypeId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void triggerNextGroup(final long rolloutId) {
|
|
||||||
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(rolloutId);
|
|
||||||
if (RolloutStatus.RUNNING != rollout.getStatus()) {
|
|
||||||
throw new RolloutIllegalStateException("Rollout is not in running state");
|
|
||||||
}
|
|
||||||
final List<RolloutGroup> groups = rollout.getRolloutGroups();
|
|
||||||
|
|
||||||
final boolean isNextGroupTriggerable = groups.stream()
|
|
||||||
.anyMatch(g -> RolloutGroupStatus.SCHEDULED.equals(g.getStatus()));
|
|
||||||
|
|
||||||
if (!isNextGroupTriggerable) {
|
|
||||||
throw new RolloutIllegalStateException("Rollout does not have any groups left to be triggered");
|
|
||||||
}
|
|
||||||
|
|
||||||
final RolloutGroup latestRunning = groups.stream()
|
|
||||||
.sorted(Comparator.comparingLong(RolloutGroup::getId).reversed())
|
|
||||||
.filter(g -> RolloutGroupStatus.RUNNING.equals(g.getStatus()))
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> new RolloutIllegalStateException("No group is running"));
|
|
||||||
|
|
||||||
startNextRolloutGroupAction.exec(rollout, latestRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TargetCount calculateTargets(final String targetFilter, final Long createdAt, final Long dsTypeId) {
|
private TargetCount calculateTargets(final String targetFilter, final Long createdAt, final Long dsTypeId) {
|
||||||
String baseFilter;
|
String baseFilter;
|
||||||
long totalTargets;
|
long totalTargets;
|
||||||
@@ -839,7 +827,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
totalTargets = targetManagement.countByRsqlAndCompatible(baseFilter, dsTypeId);
|
totalTargets = targetManagement.countByRsqlAndCompatible(baseFilter, dsTypeId);
|
||||||
} else {
|
} else {
|
||||||
totalTargets = targetManagement.countByFailedInRollout(
|
totalTargets = targetManagement.countByFailedInRollout(
|
||||||
RolloutHelper.getIdFromRetriedTargetFilter(targetFilter), dsTypeId);
|
RolloutHelper.getIdFromRetriedTargetFilter(targetFilter), dsTypeId);
|
||||||
baseFilter = targetFilter;
|
baseFilter = targetFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,15 +22,6 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.Tuple;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Expression;
|
|
||||||
import jakarta.persistence.criteria.JoinType;
|
|
||||||
import jakarta.persistence.criteria.ListJoin;
|
|
||||||
import jakarta.persistence.criteria.Order;
|
|
||||||
import jakarta.persistence.criteria.Predicate;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.ArtifactEncryptionService;
|
import org.eclipse.hawkbit.repository.ArtifactEncryptionService;
|
||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
@@ -47,14 +38,11 @@ import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
|||||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleCreate;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleCreate;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataCreate;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataCreate;
|
||||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_;
|
||||||
@@ -68,7 +56,6 @@ import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
|||||||
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification;
|
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification;
|
||||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||||
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
|
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||||
@@ -80,10 +67,7 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Slice;
|
import org.springframework.data.domain.Slice;
|
||||||
import org.springframework.data.domain.SliceImpl;
|
|
||||||
import org.springframework.data.domain.Sort;
|
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.data.jpa.repository.query.QueryUtils;
|
|
||||||
import org.springframework.orm.jpa.vendor.Database;
|
import org.springframework.orm.jpa.vendor.Database;
|
||||||
import org.springframework.retry.annotation.Backoff;
|
import org.springframework.retry.annotation.Backoff;
|
||||||
import org.springframework.retry.annotation.Retryable;
|
import org.springframework.retry.annotation.Retryable;
|
||||||
@@ -133,23 +117,20 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public SoftwareModule update(final SoftwareModuleUpdate u) {
|
public List<SoftwareModule> create(final Collection<SoftwareModuleCreate> swModules) {
|
||||||
final GenericSoftwareModuleUpdate update = (GenericSoftwareModuleUpdate) u;
|
final List<JpaSoftwareModule> modulesToCreate = swModules.stream().map(JpaSoftwareModuleCreate.class::cast)
|
||||||
|
.map(JpaSoftwareModuleCreate::build).toList();
|
||||||
|
|
||||||
final JpaSoftwareModule module = softwareModuleRepository.findById(update.getId())
|
final List<SoftwareModule> createdModules = Collections
|
||||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, update.getId()));
|
.unmodifiableList(softwareModuleRepository.saveAll(AccessController.Operation.CREATE, modulesToCreate));
|
||||||
|
|
||||||
update.getDescription().ifPresent(module::setDescription);
|
if (createdModules.stream().anyMatch(SoftwareModule::isEncrypted)) {
|
||||||
update.getVendor().ifPresent(module::setVendor);
|
entityManager.flush();
|
||||||
|
createdModules.stream().filter(SoftwareModule::isEncrypted).map(SoftwareModule::getId)
|
||||||
// lock/unlock ONLY if locked flag is present!
|
.forEach(encryptedModuleId -> ArtifactEncryptionService.getInstance()
|
||||||
if (Boolean.TRUE.equals(update.locked())) {
|
.addSoftwareModuleEncryptionSecrets(encryptedModuleId));
|
||||||
module.lock();
|
|
||||||
} else if (Boolean.FALSE.equals(update.locked())) {
|
|
||||||
module.unlock();
|
|
||||||
}
|
}
|
||||||
|
return createdModules;
|
||||||
return softwareModuleRepository.save(module);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -173,61 +154,36 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public List<SoftwareModule> create(final Collection<SoftwareModuleCreate> swModules) {
|
public SoftwareModule update(final SoftwareModuleUpdate u) {
|
||||||
final List<JpaSoftwareModule> modulesToCreate = swModules.stream().map(JpaSoftwareModuleCreate.class::cast)
|
final GenericSoftwareModuleUpdate update = (GenericSoftwareModuleUpdate) u;
|
||||||
.map(JpaSoftwareModuleCreate::build).toList();
|
|
||||||
|
|
||||||
final List<SoftwareModule> createdModules = Collections
|
final JpaSoftwareModule module = softwareModuleRepository.findById(update.getId())
|
||||||
.unmodifiableList(softwareModuleRepository.saveAll(AccessController.Operation.CREATE, modulesToCreate));
|
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, update.getId()));
|
||||||
|
|
||||||
if (createdModules.stream().anyMatch(SoftwareModule::isEncrypted)) {
|
update.getDescription().ifPresent(module::setDescription);
|
||||||
entityManager.flush();
|
update.getVendor().ifPresent(module::setVendor);
|
||||||
createdModules.stream().filter(SoftwareModule::isEncrypted).map(SoftwareModule::getId)
|
|
||||||
.forEach(encryptedModuleId -> ArtifactEncryptionService.getInstance()
|
// lock/unlock ONLY if locked flag is present!
|
||||||
.addSoftwareModuleEncryptionSecrets(encryptedModuleId));
|
if (Boolean.TRUE.equals(update.locked())) {
|
||||||
|
module.lock();
|
||||||
|
} else if (Boolean.FALSE.equals(update.locked())) {
|
||||||
|
module.unlock();
|
||||||
}
|
}
|
||||||
return createdModules;
|
|
||||||
|
return softwareModuleRepository.save(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice<SoftwareModule> findByType(final Pageable pageable, final long typeId) {
|
public long count() {
|
||||||
assertSoftwareModuleTypeExists(typeId);
|
return softwareModuleRepository.count(SoftwareModuleSpecification.isNotDeleted());
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(
|
|
||||||
softwareModuleRepository,
|
|
||||||
pageable,
|
|
||||||
List.of(
|
|
||||||
SoftwareModuleSpecification.equalType(typeId),
|
|
||||||
SoftwareModuleSpecification.isNotDeleted()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<SoftwareModule> get(final long id) {
|
@Transactional
|
||||||
return softwareModuleRepository.findById(id).map(SoftwareModule.class::cast);
|
@Retryable(include = {
|
||||||
}
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void delete(final long id) {
|
||||||
@Override
|
delete(List.of(id));
|
||||||
public Optional<SoftwareModule> getByNameAndVersionAndType(final String name, final String version,
|
|
||||||
final long typeId) {
|
|
||||||
assertSoftwareModuleTypeExists(typeId);
|
|
||||||
|
|
||||||
// TODO AC - Access is restricted. This could have problem with UI when access control is enabled.
|
|
||||||
// Vaadin UI use this for validation. May need to be called via elevated access
|
|
||||||
return JpaManagementHelper
|
|
||||||
.findOneBySpec(softwareModuleRepository, List.of(
|
|
||||||
SoftwareModuleSpecification.likeNameAndVersion(name, version),
|
|
||||||
SoftwareModuleSpecification.equalType(typeId),
|
|
||||||
SoftwareModuleSpecification.fetchType()))
|
|
||||||
.map(SoftwareModule.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
|
||||||
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
|
||||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
|
||||||
for (final Artifact localArtifact : swModule.getArtifacts()) {
|
|
||||||
((JpaArtifactManagement)artifactManagement)
|
|
||||||
.clearArtifactBinary(localArtifact.getSha1Hash());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -279,6 +235,21 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SoftwareModule> get(final Collection<Long> ids) {
|
||||||
|
return Collections.unmodifiableList(softwareModuleRepository.findAllById(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists(final long id) {
|
||||||
|
return softwareModuleRepository.existsById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<SoftwareModule> get(final long id) {
|
||||||
|
return softwareModuleRepository.findById(id).map(SoftwareModule.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice<SoftwareModule> findAll(final Pageable pageable) {
|
public Slice<SoftwareModule> findAll(final Pageable pageable) {
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, pageable, List.of(
|
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, pageable, List.of(
|
||||||
@@ -286,11 +257,6 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
SoftwareModuleSpecification.fetchType()));
|
SoftwareModuleSpecification.fetchType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count() {
|
|
||||||
return softwareModuleRepository.count(SoftwareModuleSpecification.isNotDeleted());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<SoftwareModule> findByRsql(final Pageable pageable, final String rsqlParam) {
|
public Page<SoftwareModule> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, pageable, List.of(
|
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, pageable, List.of(
|
||||||
@@ -299,70 +265,6 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
SoftwareModuleSpecification.isNotDeleted()));
|
SoftwareModuleSpecification.isNotDeleted()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<SoftwareModule> get(final Collection<Long> ids) {
|
|
||||||
return Collections.unmodifiableList(softwareModuleRepository.findAllById(ids));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<SoftwareModule> findByTextAndType(final Pageable pageable, final String searchText,
|
|
||||||
final Long typeId) {
|
|
||||||
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
|
|
||||||
specList.add(SoftwareModuleSpecification.isNotDeleted());
|
|
||||||
|
|
||||||
if (!ObjectUtils.isEmpty(searchText)) {
|
|
||||||
specList.add(buildSmSearchQuerySpec(searchText));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null != typeId) {
|
|
||||||
assertSoftwareModuleTypeExists(typeId);
|
|
||||||
specList.add(SoftwareModuleSpecification.equalType(typeId));
|
|
||||||
}
|
|
||||||
|
|
||||||
specList.add(SoftwareModuleSpecification.fetchType());
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, pageable, specList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Specification<JpaSoftwareModule> buildSmSearchQuerySpec(final String searchText) {
|
|
||||||
final String[] smFilterNameAndVersionEntries = JpaManagementHelper
|
|
||||||
.getFilterNameAndVersionEntries(searchText.trim());
|
|
||||||
return SoftwareModuleSpecification.likeNameAndVersion(smFilterNameAndVersionEntries[0],
|
|
||||||
smFilterNameAndVersionEntries[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<SoftwareModule> findByAssignedTo(final Pageable pageable, final long distributionSetId) {
|
|
||||||
assertDistributionSetExists(distributionSetId);
|
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, pageable,
|
|
||||||
Collections.singletonList(SoftwareModuleSpecification.byAssignedToDs(distributionSetId)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long countByAssignedTo(final long distributionSetId) {
|
|
||||||
assertDistributionSetExists(distributionSetId);
|
|
||||||
|
|
||||||
return softwareModuleRepository.count(SoftwareModuleSpecification.byAssignedToDs(distributionSetId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public SoftwareModuleMetadata createMetaData(final SoftwareModuleMetadataCreate c) {
|
|
||||||
final JpaSoftwareModuleMetadataCreate create = (JpaSoftwareModuleMetadataCreate) c;
|
|
||||||
final Long id = create.getSoftwareModuleId();
|
|
||||||
|
|
||||||
assertSoftwareModuleExists(id);
|
|
||||||
assertMetaDataQuota(id, 1);
|
|
||||||
|
|
||||||
// touch to update revision and last modified timestamp
|
|
||||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, (JpaSoftwareModule) get(id)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
|
||||||
return saveMetadata(create);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -400,56 +302,21 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<JpaSoftwareModuleMetadataCreate> createJpaMetadataCreateStream(
|
|
||||||
final Collection<SoftwareModuleMetadataCreate> create) {
|
|
||||||
return create.stream().map(JpaSoftwareModuleMetadataCreate.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SoftwareModuleMetadata saveMetadata(final JpaSoftwareModuleMetadataCreate create) {
|
|
||||||
assertSoftwareModuleMetadataDoesNotExist(create.getSoftwareModuleId(), create);
|
|
||||||
return softwareModuleMetadataRepository.save(create.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertSoftwareModuleMetadataDoesNotExist(final Long id,
|
|
||||||
final JpaSoftwareModuleMetadataCreate md) {
|
|
||||||
if (softwareModuleMetadataRepository.existsById(new SwMetadataCompositeKey(id, md.getKey()))) {
|
|
||||||
throw new EntityAlreadyExistsException("Metadata entry with key '" + md.getKey() + "' already exists!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts the meta data quota for the software module with the given ID.
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* The software module ID.
|
|
||||||
* @param requested
|
|
||||||
* Number of meta data entries to be created.
|
|
||||||
*/
|
|
||||||
private void assertMetaDataQuota(final Long id, final int requested) {
|
|
||||||
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerSoftwareModule();
|
|
||||||
QuotaHelper.assertAssignmentQuota(id, requested, maxMetaData, SoftwareModuleMetadata.class,
|
|
||||||
SoftwareModule.class, softwareModuleMetadataRepository::countBySoftwareModuleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public SoftwareModuleMetadata updateMetaData(final SoftwareModuleMetadataUpdate u) {
|
public SoftwareModuleMetadata createMetaData(final SoftwareModuleMetadataCreate c) {
|
||||||
final GenericSoftwareModuleMetadataUpdate update = (GenericSoftwareModuleMetadataUpdate) u;
|
final JpaSoftwareModuleMetadataCreate create = (JpaSoftwareModuleMetadataCreate) c;
|
||||||
|
final Long id = create.getSoftwareModuleId();
|
||||||
|
|
||||||
// check if exists otherwise throw entity not found exception
|
assertSoftwareModuleExists(id);
|
||||||
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) getMetaDataBySoftwareModuleId(
|
assertMetaDataQuota(id, 1);
|
||||||
update.getSoftwareModuleId(), update.getKey())
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleMetadata.class,
|
|
||||||
update.getSoftwareModuleId(), update.getKey()));
|
|
||||||
|
|
||||||
update.getValue().ifPresent(metadata::setValue);
|
// touch to update revision and last modified timestamp
|
||||||
update.isTargetVisible().ifPresent(metadata::setTargetVisible);
|
JpaManagementHelper.touch(entityManager, softwareModuleRepository, (JpaSoftwareModule) get(id)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository,
|
return saveMetadata(create);
|
||||||
(JpaSoftwareModule) metadata.getSoftwareModule());
|
|
||||||
return softwareModuleMetadataRepository.save(metadata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -466,14 +333,61 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<SoftwareModuleMetadata> findMetaDataByRsql(final Pageable pageable, final long id,
|
public Page<SoftwareModule> findByAssignedTo(final Pageable pageable, final long distributionSetId) {
|
||||||
final String rsqlParam) {
|
assertDistributionSetExists(distributionSetId);
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, pageable,
|
||||||
|
Collections.singletonList(SoftwareModuleSpecification.byAssignedToDs(distributionSetId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countByAssignedTo(final long distributionSetId) {
|
||||||
|
assertDistributionSetExists(distributionSetId);
|
||||||
|
|
||||||
|
return softwareModuleRepository.count(SoftwareModuleSpecification.byAssignedToDs(distributionSetId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<SoftwareModule> findByTextAndType(final Pageable pageable, final String searchText,
|
||||||
|
final Long typeId) {
|
||||||
|
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
|
||||||
|
specList.add(SoftwareModuleSpecification.isNotDeleted());
|
||||||
|
|
||||||
|
if (!ObjectUtils.isEmpty(searchText)) {
|
||||||
|
specList.add(buildSmSearchQuerySpec(searchText));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != typeId) {
|
||||||
|
assertSoftwareModuleTypeExists(typeId);
|
||||||
|
specList.add(SoftwareModuleSpecification.equalType(typeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
specList.add(SoftwareModuleSpecification.fetchType());
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, pageable, specList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<SoftwareModule> getByNameAndVersionAndType(final String name, final String version,
|
||||||
|
final long typeId) {
|
||||||
|
assertSoftwareModuleTypeExists(typeId);
|
||||||
|
|
||||||
|
// TODO AC - Access is restricted. This could have problem with UI when access control is enabled.
|
||||||
|
// Vaadin UI use this for validation. May need to be called via elevated access
|
||||||
|
return JpaManagementHelper
|
||||||
|
.findOneBySpec(softwareModuleRepository, List.of(
|
||||||
|
SoftwareModuleSpecification.likeNameAndVersion(name, version),
|
||||||
|
SoftwareModuleSpecification.equalType(typeId),
|
||||||
|
SoftwareModuleSpecification.fetchType()))
|
||||||
|
.map(SoftwareModule.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<SoftwareModuleMetadata> getMetaDataBySoftwareModuleId(final long id, final String key) {
|
||||||
assertSoftwareModuleExists(id);
|
assertSoftwareModuleExists(id);
|
||||||
|
|
||||||
final List<Specification<JpaSoftwareModuleMetadata>> specList = Arrays
|
return softwareModuleMetadataRepository.findById(new SwMetadataCompositeKey(id, key))
|
||||||
.asList(RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleMetadataFields.class,
|
.map(SoftwareModuleMetadata.class::cast);
|
||||||
virtualPropertyReplacer, database), metadataBySoftwareModuleIdSpec(id));
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleMetadataRepository, pageable, specList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -492,11 +406,35 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<SoftwareModuleMetadata> getMetaDataBySoftwareModuleId(final long id, final String key) {
|
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(final Pageable pageable,
|
||||||
|
final long id) {
|
||||||
assertSoftwareModuleExists(id);
|
assertSoftwareModuleExists(id);
|
||||||
|
|
||||||
return softwareModuleMetadataRepository.findById(new SwMetadataCompositeKey(id, key))
|
return JpaManagementHelper.convertPage(softwareModuleMetadataRepository.findBySoftwareModuleIdAndTargetVisible(
|
||||||
.map(SoftwareModuleMetadata.class::cast);
|
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), id, true), pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<SoftwareModuleMetadata> findMetaDataByRsql(final Pageable pageable, final long id,
|
||||||
|
final String rsqlParam) {
|
||||||
|
assertSoftwareModuleExists(id);
|
||||||
|
|
||||||
|
final List<Specification<JpaSoftwareModuleMetadata>> specList = Arrays
|
||||||
|
.asList(RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleMetadataFields.class,
|
||||||
|
virtualPropertyReplacer, database), metadataBySoftwareModuleIdSpec(id));
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleMetadataRepository, pageable, specList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice<SoftwareModule> findByType(final Pageable pageable, final long typeId) {
|
||||||
|
assertSoftwareModuleTypeExists(typeId);
|
||||||
|
|
||||||
|
return JpaManagementHelper.findAllWithoutCountBySpec(
|
||||||
|
softwareModuleRepository,
|
||||||
|
pageable,
|
||||||
|
List.of(
|
||||||
|
SoftwareModuleSpecification.equalType(typeId),
|
||||||
|
SoftwareModuleSpecification.isNotDeleted()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -531,22 +469,71 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public void delete(final long id) {
|
public SoftwareModuleMetadata updateMetaData(final SoftwareModuleMetadataUpdate u) {
|
||||||
delete(List.of(id));
|
final GenericSoftwareModuleMetadataUpdate update = (GenericSoftwareModuleMetadataUpdate) u;
|
||||||
|
|
||||||
|
// check if exists otherwise throw entity not found exception
|
||||||
|
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) getMetaDataBySoftwareModuleId(
|
||||||
|
update.getSoftwareModuleId(), update.getKey())
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleMetadata.class,
|
||||||
|
update.getSoftwareModuleId(), update.getKey()));
|
||||||
|
|
||||||
|
update.getValue().ifPresent(metadata::setValue);
|
||||||
|
update.isTargetVisible().ifPresent(metadata::setTargetVisible);
|
||||||
|
|
||||||
|
JpaManagementHelper.touch(entityManager, softwareModuleRepository,
|
||||||
|
(JpaSoftwareModule) metadata.getSoftwareModule());
|
||||||
|
return softwareModuleMetadataRepository.save(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static Stream<JpaSoftwareModuleMetadataCreate> createJpaMetadataCreateStream(
|
||||||
public boolean exists(final long id) {
|
final Collection<SoftwareModuleMetadataCreate> create) {
|
||||||
return softwareModuleRepository.existsById(id);
|
return create.stream().map(JpaSoftwareModuleMetadataCreate.class::cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static Specification<JpaSoftwareModuleMetadata> metadataBySoftwareModuleIdSpec(final long id) {
|
||||||
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(final Pageable pageable,
|
return (root, query, cb) -> cb
|
||||||
final long id) {
|
.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id), id);
|
||||||
assertSoftwareModuleExists(id);
|
}
|
||||||
|
|
||||||
return JpaManagementHelper.convertPage(softwareModuleMetadataRepository.findBySoftwareModuleIdAndTargetVisible(
|
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
||||||
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), id, true), pageable);
|
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
||||||
|
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
||||||
|
for (final Artifact localArtifact : swModule.getArtifacts()) {
|
||||||
|
((JpaArtifactManagement) artifactManagement)
|
||||||
|
.clearArtifactBinary(localArtifact.getSha1Hash());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Specification<JpaSoftwareModule> buildSmSearchQuerySpec(final String searchText) {
|
||||||
|
final String[] smFilterNameAndVersionEntries = JpaManagementHelper
|
||||||
|
.getFilterNameAndVersionEntries(searchText.trim());
|
||||||
|
return SoftwareModuleSpecification.likeNameAndVersion(smFilterNameAndVersionEntries[0],
|
||||||
|
smFilterNameAndVersionEntries[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SoftwareModuleMetadata saveMetadata(final JpaSoftwareModuleMetadataCreate create) {
|
||||||
|
assertSoftwareModuleMetadataDoesNotExist(create.getSoftwareModuleId(), create);
|
||||||
|
return softwareModuleMetadataRepository.save(create.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSoftwareModuleMetadataDoesNotExist(final Long id,
|
||||||
|
final JpaSoftwareModuleMetadataCreate md) {
|
||||||
|
if (softwareModuleMetadataRepository.existsById(new SwMetadataCompositeKey(id, md.getKey()))) {
|
||||||
|
throw new EntityAlreadyExistsException("Metadata entry with key '" + md.getKey() + "' already exists!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts the meta data quota for the software module with the given ID.
|
||||||
|
*
|
||||||
|
* @param id The software module ID.
|
||||||
|
* @param requested Number of meta data entries to be created.
|
||||||
|
*/
|
||||||
|
private void assertMetaDataQuota(final Long id, final int requested) {
|
||||||
|
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerSoftwareModule();
|
||||||
|
QuotaHelper.assertAssignmentQuota(id, requested, maxMetaData, SoftwareModuleMetadata.class,
|
||||||
|
SoftwareModule.class, softwareModuleMetadataRepository::countBySoftwareModuleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSoftwareModuleExists(final Long id) {
|
private void assertSoftwareModuleExists(final Long id) {
|
||||||
@@ -566,9 +553,4 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Specification<JpaSoftwareModuleMetadata> metadataBySoftwareModuleIdSpec(final long id) {
|
|
||||||
return (root, query, cb) -> cb
|
|
||||||
.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id), id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of {@link SoftwareModuleTypeManagement}.
|
* JPA implementation of {@link SoftwareModuleTypeManagement}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
@@ -68,6 +67,37 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
|||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<SoftwareModuleType> getByKey(final String key) {
|
||||||
|
return softwareModuleTypeRepository.findByKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<SoftwareModuleType> getByName(final String name) {
|
||||||
|
return softwareModuleTypeRepository.findByName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public List<SoftwareModuleType> create(final Collection<SoftwareModuleTypeCreate> c) {
|
||||||
|
final List<JpaSoftwareModuleType> creates = c.stream().map(JpaSoftwareModuleTypeCreate.class::cast)
|
||||||
|
.map(JpaSoftwareModuleTypeCreate::build).toList();
|
||||||
|
return Collections.unmodifiableList(
|
||||||
|
softwareModuleTypeRepository.saveAll(AccessController.Operation.CREATE, creates));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public SoftwareModuleType create(final SoftwareModuleTypeCreate c) {
|
||||||
|
final JpaSoftwareModuleTypeCreate create = (JpaSoftwareModuleTypeCreate) c;
|
||||||
|
|
||||||
|
return softwareModuleTypeRepository.save(AccessController.Operation.CREATE, create.build());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -84,46 +114,11 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
|||||||
return softwareModuleTypeRepository.save(type);
|
return softwareModuleTypeRepository.save(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<SoftwareModuleType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleTypeRepository, pageable,
|
|
||||||
List.of(
|
|
||||||
RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleTypeFields.class,
|
|
||||||
virtualPropertyReplacer, database),
|
|
||||||
SoftwareModuleTypeSpecification.isNotDeleted()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Slice<SoftwareModuleType> findAll(final Pageable pageable) {
|
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleTypeRepository, pageable,
|
|
||||||
List.of(SoftwareModuleTypeSpecification.isNotDeleted()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long count() {
|
public long count() {
|
||||||
return softwareModuleTypeRepository.count(SoftwareModuleTypeSpecification.isNotDeleted());
|
return softwareModuleTypeRepository.count(SoftwareModuleTypeSpecification.isNotDeleted());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<SoftwareModuleType> getByKey(final String key) {
|
|
||||||
return softwareModuleTypeRepository.findByKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<SoftwareModuleType> getByName(final String name) {
|
|
||||||
return softwareModuleTypeRepository.findByName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public SoftwareModuleType create(final SoftwareModuleTypeCreate c) {
|
|
||||||
final JpaSoftwareModuleTypeCreate create = (JpaSoftwareModuleTypeCreate) c;
|
|
||||||
|
|
||||||
return softwareModuleTypeRepository.save(AccessController.Operation.CREATE, create.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -135,17 +130,6 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
|||||||
delete(toDelete);
|
delete(toDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public List<SoftwareModuleType> create(final Collection<SoftwareModuleTypeCreate> c) {
|
|
||||||
final List<JpaSoftwareModuleType> creates = c.stream().map(JpaSoftwareModuleTypeCreate.class::cast)
|
|
||||||
.map(JpaSoftwareModuleTypeCreate::build).toList();
|
|
||||||
return Collections.unmodifiableList(
|
|
||||||
softwareModuleTypeRepository.saveAll(AccessController.Operation.CREATE, creates));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
@@ -161,14 +145,29 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
|||||||
return Collections.unmodifiableList(softwareModuleTypeRepository.findAllById(ids));
|
return Collections.unmodifiableList(softwareModuleTypeRepository.findAllById(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists(final long id) {
|
||||||
|
return softwareModuleTypeRepository.existsById(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<SoftwareModuleType> get(final long id) {
|
public Optional<SoftwareModuleType> get(final long id) {
|
||||||
return softwareModuleTypeRepository.findById(id).map(SoftwareModuleType.class::cast);
|
return softwareModuleTypeRepository.findById(id).map(SoftwareModuleType.class::cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists(final long id) {
|
public Slice<SoftwareModuleType> findAll(final Pageable pageable) {
|
||||||
return softwareModuleTypeRepository.existsById(id);
|
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleTypeRepository, pageable,
|
||||||
|
List.of(SoftwareModuleTypeSpecification.isNotDeleted()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<SoftwareModuleType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleTypeRepository, pageable,
|
||||||
|
List.of(
|
||||||
|
RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleTypeFields.class,
|
||||||
|
virtualPropertyReplacer, database),
|
||||||
|
SoftwareModuleTypeSpecification.isNotDeleted()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delete(JpaSoftwareModuleType toDelete) {
|
private void delete(JpaSoftwareModuleType toDelete) {
|
||||||
|
|||||||
@@ -74,81 +74,57 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement {
|
public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement {
|
||||||
|
|
||||||
private static final int MAX_TENANTS_QUERY = 1000;
|
private static final int MAX_TENANTS_QUERY = 1000;
|
||||||
|
private final String countArtifactQuery;
|
||||||
|
private final String countSoftwareModulesQuery;
|
||||||
@Autowired
|
@Autowired
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TargetRepository targetRepository;
|
private TargetRepository targetRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TargetFilterQueryRepository targetFilterQueryRepository;
|
private TargetFilterQueryRepository targetFilterQueryRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DistributionSetRepository distributionSetRepository;
|
private DistributionSetRepository distributionSetRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SoftwareModuleRepository softwareModuleRepository;
|
private SoftwareModuleRepository softwareModuleRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantMetaDataRepository tenantMetaDataRepository;
|
private TenantMetaDataRepository tenantMetaDataRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DistributionSetTypeRepository distributionSetTypeRepository;
|
private DistributionSetTypeRepository distributionSetTypeRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
private SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TargetTagRepository targetTagRepository;
|
private TargetTagRepository targetTagRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TargetTypeRepository targetTypeRepository;
|
private TargetTypeRepository targetTypeRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DistributionSetTagRepository distributionSetTagRepository;
|
private DistributionSetTagRepository distributionSetTagRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantConfigurationRepository tenantConfigurationRepository;
|
private TenantConfigurationRepository tenantConfigurationRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RolloutRepository rolloutRepository;
|
private RolloutRepository rolloutRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantAware tenantAware;
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantStatsManagement systemStatsManagement;
|
private TenantStatsManagement systemStatsManagement;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenancyCacheManager cacheManager;
|
private TenancyCacheManager cacheManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator;
|
private SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemSecurityContext systemSecurityContext;
|
private SystemSecurityContext systemSecurityContext;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlatformTransactionManager txManager;
|
private PlatformTransactionManager txManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RolloutStatusCache rolloutStatusCache;
|
private RolloutStatusCache rolloutStatusCache;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ArtifactRepository artifactRepository;
|
private ArtifactRepository artifactRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RepositoryProperties repositoryProperties;
|
private RepositoryProperties repositoryProperties;
|
||||||
|
|
||||||
private final String countArtifactQuery;
|
|
||||||
private final String countSoftwareModulesQuery;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param properties
|
* @param properties properties to get the underlying database
|
||||||
* properties to get the underlying database
|
|
||||||
*/
|
*/
|
||||||
public JpaSystemManagement(final JpaProperties properties) {
|
public JpaSystemManagement(final JpaProperties properties) {
|
||||||
|
|
||||||
@@ -159,48 +135,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
+ isDeleted;
|
+ isDeleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public SystemUsageReport getSystemUsageStatistics() {
|
|
||||||
|
|
||||||
final Number count = (Number) entityManager.createNativeQuery(countSoftwareModulesQuery).getSingleResult();
|
|
||||||
|
|
||||||
long sumOfArtifacts = 0;
|
|
||||||
if (count != null) {
|
|
||||||
sumOfArtifacts = count.longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// we use native queries to punch through the tenant boundaries. This
|
|
||||||
// has to be used with care!
|
|
||||||
final long targets = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_target")
|
|
||||||
.getSingleResult()).longValue();
|
|
||||||
|
|
||||||
final long artifacts = ((Number) entityManager.createNativeQuery(countArtifactQuery).getSingleResult())
|
|
||||||
.longValue();
|
|
||||||
|
|
||||||
final long actions = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_action")
|
|
||||||
.getSingleResult()).longValue();
|
|
||||||
|
|
||||||
return new SystemUsageReportWithTenants(targets, artifacts, actions, sumOfArtifacts,
|
|
||||||
tenantMetaDataRepository.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isPostgreSql(final JpaProperties properties) {
|
|
||||||
return Database.POSTGRESQL == properties.getDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SystemUsageReportWithTenants getSystemUsageStatisticsWithTenants() {
|
|
||||||
final SystemUsageReportWithTenants result = (SystemUsageReportWithTenants) getSystemUsageStatistics();
|
|
||||||
|
|
||||||
usageStatsPerTenant(result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void usageStatsPerTenant(final SystemUsageReportWithTenants report) {
|
|
||||||
forEachTenant(tenant -> report.addTenantData(systemStatsManagement.getStatsOfTenant()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = Propagation.SUPPORTS)
|
@Transactional(propagation = Propagation.SUPPORTS)
|
||||||
public KeyGenerator currentTenantKeyGenerator() {
|
public KeyGenerator currentTenantKeyGenerator() {
|
||||||
@@ -208,18 +142,13 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TenantMetaData createTenantMetadata(final String tenant) {
|
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager", unless = "#result == null")
|
||||||
final TenantMetaData result = tenantMetaDataRepository.findByTenantIgnoreCase(tenant);
|
public String currentTenant() {
|
||||||
// Create if it does not exist
|
return currentTenantCacheKeyGenerator.getTenantInCreation().orElseGet(() -> {
|
||||||
if (result == null) {
|
final TenantMetaData findByTenant = tenantMetaDataRepository
|
||||||
return createTenantMetadata0(tenant);
|
.findByTenantIgnoreCase(tenantAware.getCurrentTenant());
|
||||||
}
|
return findByTenant != null ? findByTenant.getTenant() : null;
|
||||||
return result;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<String> findTenants(final Pageable pageable) {
|
|
||||||
return tenantMetaDataRepository.findTenants(pageable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -249,6 +178,70 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<String> findTenants(final Pageable pageable) {
|
||||||
|
return tenantMetaDataRepository.findTenants(pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||||
|
// Exception squid:S2229 - calling findTenants without transaction is
|
||||||
|
// intended in this case
|
||||||
|
@SuppressWarnings("squid:S2229")
|
||||||
|
public void forEachTenant(final Consumer<String> consumer) {
|
||||||
|
Page<String> tenants;
|
||||||
|
Pageable query = PageRequest.of(0, MAX_TENANTS_QUERY);
|
||||||
|
do {
|
||||||
|
tenants = findTenants(query);
|
||||||
|
tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> {
|
||||||
|
try {
|
||||||
|
consumer.accept(tenant);
|
||||||
|
} catch (final RuntimeException ex) {
|
||||||
|
log.debug("Exception on forEachTenant execution for tenant {}. Continue with next tenant.",
|
||||||
|
tenant, ex);
|
||||||
|
log.error("Exception on forEachTenant execution for tenant {} with error message [{}]. "
|
||||||
|
+ "Continue with next tenant.", tenant, ex.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
} while ((query = tenants.nextPageable()) != Pageable.unpaged());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SystemUsageReportWithTenants getSystemUsageStatisticsWithTenants() {
|
||||||
|
final SystemUsageReportWithTenants result = (SystemUsageReportWithTenants) getSystemUsageStatistics();
|
||||||
|
|
||||||
|
usageStatsPerTenant(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SystemUsageReport getSystemUsageStatistics() {
|
||||||
|
|
||||||
|
final Number count = (Number) entityManager.createNativeQuery(countSoftwareModulesQuery).getSingleResult();
|
||||||
|
|
||||||
|
long sumOfArtifacts = 0;
|
||||||
|
if (count != null) {
|
||||||
|
sumOfArtifacts = count.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// we use native queries to punch through the tenant boundaries. This
|
||||||
|
// has to be used with care!
|
||||||
|
final long targets = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_target")
|
||||||
|
.getSingleResult()).longValue();
|
||||||
|
|
||||||
|
final long artifacts = ((Number) entityManager.createNativeQuery(countArtifactQuery).getSingleResult())
|
||||||
|
.longValue();
|
||||||
|
|
||||||
|
final long actions = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_action")
|
||||||
|
.getSingleResult()).longValue();
|
||||||
|
|
||||||
|
return new SystemUsageReportWithTenants(targets, artifacts, actions, sumOfArtifacts,
|
||||||
|
tenantMetaDataRepository.count());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TenantMetaData getTenantMetadata() {
|
public TenantMetaData getTenantMetadata() {
|
||||||
final String tenant = tenantAware.getCurrentTenant();
|
final String tenant = tenantAware.getCurrentTenant();
|
||||||
@@ -270,13 +263,13 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager", unless = "#result == null")
|
public TenantMetaData createTenantMetadata(final String tenant) {
|
||||||
public String currentTenant() {
|
final TenantMetaData result = tenantMetaDataRepository.findByTenantIgnoreCase(tenant);
|
||||||
return currentTenantCacheKeyGenerator.getTenantInCreation().orElseGet(() -> {
|
// Create if it does not exist
|
||||||
final TenantMetaData findByTenant = tenantMetaDataRepository
|
if (result == null) {
|
||||||
.findByTenantIgnoreCase(tenantAware.getCurrentTenant());
|
return createTenantMetadata0(tenant);
|
||||||
return findByTenant != null ? findByTenant.getTenant() : null;
|
}
|
||||||
});
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -292,6 +285,20 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
return tenantMetaDataRepository.save(data);
|
return tenantMetaDataRepository.save(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TenantMetaData getTenantMetadata(final long tenantId) {
|
||||||
|
return tenantMetaDataRepository.findById(tenantId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(TenantMetaData.class, tenantId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPostgreSql(final JpaProperties properties) {
|
||||||
|
return Database.POSTGRESQL == properties.getDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void usageStatsPerTenant(final SystemUsageReportWithTenants report) {
|
||||||
|
forEachTenant(tenant -> report.addTenantData(systemStatsManagement.getStatsOfTenant()));
|
||||||
|
}
|
||||||
|
|
||||||
private DistributionSetType createStandardSoftwareDataSetup() {
|
private DistributionSetType createStandardSoftwareDataSetup() {
|
||||||
final SoftwareModuleType app = softwareModuleTypeRepository
|
final SoftwareModuleType app = softwareModuleTypeRepository
|
||||||
.save(new JpaSoftwareModuleType(org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_APP_KEY,
|
.save(new JpaSoftwareModuleType(org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_APP_KEY,
|
||||||
@@ -318,38 +325,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
.save(new JpaDistributionSetType(org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_OS_WITH_APPS_KEY,
|
.save(new JpaDistributionSetType(org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_OS_WITH_APPS_KEY,
|
||||||
org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_OS_WITH_APPS_NAME,
|
org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_OS_WITH_APPS_NAME,
|
||||||
"Default type with Firmware/OS and optional app(s).").addMandatoryModuleType(os)
|
"Default type with Firmware/OS and optional app(s).").addMandatoryModuleType(os)
|
||||||
.addOptionalModuleType(app));
|
.addOptionalModuleType(app));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TenantMetaData getTenantMetadata(final long tenantId) {
|
|
||||||
return tenantMetaDataRepository.findById(tenantId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(TenantMetaData.class, tenantId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
|
||||||
// Exception squid:S2229 - calling findTenants without transaction is
|
|
||||||
// intended in this case
|
|
||||||
@SuppressWarnings("squid:S2229")
|
|
||||||
public void forEachTenant(final Consumer<String> consumer) {
|
|
||||||
Page<String> tenants;
|
|
||||||
Pageable query = PageRequest.of(0, MAX_TENANTS_QUERY);
|
|
||||||
do {
|
|
||||||
tenants = findTenants(query);
|
|
||||||
tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> {
|
|
||||||
try {
|
|
||||||
consumer.accept(tenant);
|
|
||||||
} catch (final RuntimeException ex) {
|
|
||||||
log.debug("Exception on forEachTenant execution for tenant {}. Continue with next tenant.",
|
|
||||||
tenant, ex);
|
|
||||||
log.error("Exception on forEachTenant execution for tenant {} with error message [{}]. "
|
|
||||||
+ "Continue with next tenant.", tenant, ex.getMessage());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}));
|
|
||||||
} while ((query = tenants.nextPageable()) != Pageable.unpaged());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TenantMetaData createTenantMetadata0(final String tenant) {
|
private TenantMetaData createTenantMetadata0(final String tenant) {
|
||||||
@@ -371,8 +347,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
* {@link MultiTenantJpaTransactionManager} is called again and set the
|
* {@link MultiTenantJpaTransactionManager} is called again and set the
|
||||||
* tenant for this transaction.
|
* tenant for this transaction.
|
||||||
*
|
*
|
||||||
* @param tenant
|
* @param tenant the tenant to be created
|
||||||
* the tenant to be created
|
|
||||||
* @return the initial created {@link TenantMetaData}
|
* @return the initial created {@link TenantMetaData}
|
||||||
*/
|
*/
|
||||||
private TenantMetaData createInitialTenantMetaData(final String tenant) {
|
private TenantMetaData createInitialTenantMetaData(final String tenant) {
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import cz.jirutka.rsql.parser.RSQLParserException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.eclipse.hawkbit.ContextAware;
|
||||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||||
@@ -25,7 +27,6 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
|
|||||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||||
import org.eclipse.hawkbit.ContextAware;
|
|
||||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||||
import org.eclipse.hawkbit.repository.builder.GenericTargetFilterQueryUpdate;
|
import org.eclipse.hawkbit.repository.builder.GenericTargetFilterQueryUpdate;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||||
@@ -64,8 +65,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import cz.jirutka.rsql.parser.RSQLParserException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of {@link TargetFilterQueryManagement}.
|
* JPA implementation of {@link TargetFilterQueryManagement}.
|
||||||
*/
|
*/
|
||||||
@@ -140,6 +139,17 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
|||||||
targetFilterQueryRepository.deleteById(targetFilterQueryId);
|
targetFilterQueryRepository.deleteById(targetFilterQueryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verifyTargetFilterQuerySyntax(final String query) {
|
||||||
|
try {
|
||||||
|
RSQLUtility.validateRsqlFor(query, TargetFields.class);
|
||||||
|
return true;
|
||||||
|
} catch (final RSQLParserException | RSQLParameterUnsupportedFieldException e) {
|
||||||
|
log.debug("The RSQL query '" + query + "' is invalid.", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice<TargetFilterQuery> findAll(final Pageable pageable) {
|
public Slice<TargetFilterQuery> findAll(final Pageable pageable) {
|
||||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetFilterQueryRepository, pageable, null);
|
return JpaManagementHelper.findAllWithoutCountBySpec(targetFilterQueryRepository, pageable, null);
|
||||||
@@ -179,7 +189,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
|||||||
public Page<TargetFilterQuery> findByRsql(final Pageable pageable, final String rsqlFilter) {
|
public Page<TargetFilterQuery> findByRsql(final Pageable pageable, final String rsqlFilter) {
|
||||||
final List<Specification<JpaTargetFilterQuery>> specList = !ObjectUtils.isEmpty(rsqlFilter)
|
final List<Specification<JpaTargetFilterQuery>> specList = !ObjectUtils.isEmpty(rsqlFilter)
|
||||||
? Collections.singletonList(RSQLUtility.buildRsqlSpecification(rsqlFilter,
|
? Collections.singletonList(RSQLUtility.buildRsqlSpecification(rsqlFilter,
|
||||||
TargetFilterQueryFields.class, virtualPropertyReplacer, database))
|
TargetFilterQueryFields.class, virtualPropertyReplacer, database))
|
||||||
: Collections.emptyList();
|
: Collections.emptyList();
|
||||||
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(targetFilterQueryRepository, pageable, specList);
|
return JpaManagementHelper.findAllWithCountBySpec(targetFilterQueryRepository, pageable, specList);
|
||||||
@@ -225,13 +235,13 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<TargetFilterQuery> getByName(final String targetFilterQueryName) {
|
public Optional<TargetFilterQuery> get(final long targetFilterQueryId) {
|
||||||
return targetFilterQueryRepository.findByName(targetFilterQueryName);
|
return targetFilterQueryRepository.findById(targetFilterQueryId).map(TargetFilterQuery.class::cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<TargetFilterQuery> get(final long targetFilterQueryId) {
|
public Optional<TargetFilterQuery> getByName(final String targetFilterQueryName) {
|
||||||
return targetFilterQueryRepository.findById(targetFilterQueryId).map(TargetFilterQuery.class::cast);
|
return targetFilterQueryRepository.findByName(targetFilterQueryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -279,7 +289,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
|||||||
final JpaDistributionSet distributionSet = (JpaDistributionSet) distributionSetManagement
|
final JpaDistributionSet distributionSet = (JpaDistributionSet) distributionSetManagement
|
||||||
.getValidAndComplete(update.getDsId());
|
.getValidAndComplete(update.getDsId());
|
||||||
|
|
||||||
if (((JpaDistributionSetManagement)distributionSetManagement).isImplicitLockApplicable(distributionSet)) {
|
if (((JpaDistributionSetManagement) distributionSetManagement).isImplicitLockApplicable(distributionSet)) {
|
||||||
distributionSetManagement.lock(distributionSet.getId());
|
distributionSetManagement.lock(distributionSet.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,9 +308,11 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
|||||||
return targetFilterQueryRepository.save(targetFilterQuery);
|
return targetFilterQueryRepository.save(targetFilterQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isConfirmationFlowEnabled() {
|
@Override
|
||||||
return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
@Transactional
|
||||||
.isConfirmationFlowEnabled();
|
public void cancelAutoAssignmentForDistributionSet(final long distributionSetId) {
|
||||||
|
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(distributionSetId);
|
||||||
|
log.debug("Auto assignments for distribution sets {} deactivated", distributionSetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionType sanitizeAutoAssignActionType(final ActionType actionType) {
|
private static ActionType sanitizeAutoAssignActionType(final ActionType actionType) {
|
||||||
@@ -315,32 +327,19 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
|||||||
return actionType;
|
return actionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isConfirmationFlowEnabled() {
|
||||||
|
return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
||||||
|
.isConfirmationFlowEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
private JpaTargetFilterQuery findTargetFilterQueryOrThrowExceptionIfNotFound(final Long queryId) {
|
private JpaTargetFilterQuery findTargetFilterQueryOrThrowExceptionIfNotFound(final Long queryId) {
|
||||||
return targetFilterQueryRepository.findById(queryId)
|
return targetFilterQueryRepository.findById(queryId)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, queryId));
|
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, queryId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean verifyTargetFilterQuerySyntax(final String query) {
|
|
||||||
try {
|
|
||||||
RSQLUtility.validateRsqlFor(query, TargetFields.class);
|
|
||||||
return true;
|
|
||||||
} catch (final RSQLParserException | RSQLParameterUnsupportedFieldException e) {
|
|
||||||
log.debug("The RSQL query '" + query + "' is invalid.", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertMaxTargetsQuota(final String query, final String filterName, final long dsId) {
|
private void assertMaxTargetsQuota(final String query, final String filterName, final long dsId) {
|
||||||
QuotaHelper.assertAssignmentQuota(filterName,
|
QuotaHelper.assertAssignmentQuota(filterName,
|
||||||
targetManagement.countByRsqlAndNonDSAndCompatibleAndUpdatable(dsId, query),
|
targetManagement.countByRsqlAndNonDSAndCompatibleAndUpdatable(dsId, query),
|
||||||
quotaManagement.getMaxTargetsPerAutoAssignment(), Target.class, TargetFilterQuery.class, null);
|
quotaManagement.getMaxTargetsPerAutoAssignment(), Target.class, TargetFilterQuery.class, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void cancelAutoAssignmentForDistributionSet(final long distributionSetId) {
|
|
||||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(distributionSetId);
|
|
||||||
log.debug("Auto assignments for distribution sets {} deactivated", distributionSetId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of {@link TargetTagManagement}.
|
* JPA implementation of {@link TargetTagManagement}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
@@ -62,8 +61,8 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<TargetTag> getByName(final String name) {
|
public long count() {
|
||||||
return targetTagRepository.findByNameEquals(name);
|
return targetTagRepository.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,8 +93,13 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
|||||||
public void delete(final String targetTagName) {
|
public void delete(final String targetTagName) {
|
||||||
targetTagRepository.delete(
|
targetTagRepository.delete(
|
||||||
targetTagRepository
|
targetTagRepository
|
||||||
.findOne(((root, query, cb) -> cb.equal(root.get(JpaTargetTag_.name), targetTagName)))
|
.findOne(((root, query, cb) -> cb.equal(root.get(JpaTargetTag_.name), targetTagName)))
|
||||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagName)));
|
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<TargetTag> findAll(final Pageable pageable) {
|
||||||
|
return JpaManagementHelper.findAllWithCountBySpec(targetTagRepository, pageable, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -105,8 +109,18 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long count() {
|
public Optional<TargetTag> getByName(final String name) {
|
||||||
return targetTagRepository.count();
|
return targetTagRepository.findByNameEquals(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<TargetTag> get(final long id) {
|
||||||
|
return targetTagRepository.findById(id).map(TargetTag.class::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TargetTag> get(final Collection<Long> ids) {
|
||||||
|
return Collections.unmodifiableList(targetTagRepository.findAllById(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,19 +139,4 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
|||||||
|
|
||||||
return targetTagRepository.save(tag);
|
return targetTagRepository.save(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<TargetTag> get(final long id) {
|
|
||||||
return targetTagRepository.findById(id).map(TargetTag.class::cast);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TargetTag> get(final Collection<Long> ids) {
|
|
||||||
return Collections.unmodifiableList(targetTagRepository.findAllById(ids));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<TargetTag> findAll(final Pageable pageable) {
|
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(targetTagRepository, pageable, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of {@link TargetTypeManagement}.
|
* JPA implementation of {@link TargetTypeManagement}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
@@ -68,14 +67,10 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param targetTypeRepository
|
* @param targetTypeRepository Target type repository
|
||||||
* Target type repository
|
* @param targetRepository Target repository
|
||||||
* @param targetRepository
|
* @param virtualPropertyReplacer replacer
|
||||||
* Target repository
|
* @param database database
|
||||||
* @param virtualPropertyReplacer
|
|
||||||
* replacer
|
|
||||||
* @param database
|
|
||||||
* database
|
|
||||||
*/
|
*/
|
||||||
public JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository,
|
public JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository,
|
||||||
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
|
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||||
@@ -152,7 +147,7 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
|||||||
return JpaManagementHelper.findAllWithCountBySpec(targetTypeRepository, pageable,
|
return JpaManagementHelper.findAllWithCountBySpec(targetTypeRepository, pageable,
|
||||||
List.of(
|
List.of(
|
||||||
RSQLUtility.buildRsqlSpecification(
|
RSQLUtility.buildRsqlSpecification(
|
||||||
rsqlParam, TargetTypeFields.class, virtualPropertyReplacer,database)));
|
rsqlParam, TargetTypeFields.class, virtualPropertyReplacer, database)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -236,13 +231,9 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
|||||||
* Enforces the quota specifying the maximum number of
|
* Enforces the quota specifying the maximum number of
|
||||||
* {@link DistributionSetType}s per {@link TargetType}.
|
* {@link DistributionSetType}s per {@link TargetType}.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id of the target type
|
||||||
* of the target type
|
* @param requested number of distribution set types to check
|
||||||
* @param requested
|
* @throws AssignmentQuotaExceededException if the software module type quota is exceeded
|
||||||
* number of distribution set types to check
|
|
||||||
*
|
|
||||||
* @throws AssignmentQuotaExceededException
|
|
||||||
* if the software module type quota is exceeded
|
|
||||||
*/
|
*/
|
||||||
private void assertDistributionSetTypeQuota(final long id, final int requested) {
|
private void assertDistributionSetTypeQuota(final long id, final int requested) {
|
||||||
QuotaHelper.assertAssignmentQuota(id, requested, quotaManagement.getMaxDistributionSetTypesPerTargetType(),
|
QuotaHelper.assertAssignmentQuota(id, requested, quotaManagement.getMaxDistributionSetTypesPerTargetType(),
|
||||||
|
|||||||
@@ -58,76 +58,18 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
@Validated
|
@Validated
|
||||||
public class JpaTenantConfigurationManagement implements TenantConfigurationManagement {
|
public class JpaTenantConfigurationManagement implements TenantConfigurationManagement {
|
||||||
|
|
||||||
|
private static final ConfigurableConversionService conversionService = new DefaultConversionService();
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantConfigurationRepository tenantConfigurationRepository;
|
private TenantConfigurationRepository tenantConfigurationRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantConfigurationProperties tenantConfigurationProperties;
|
private TenantConfigurationProperties tenantConfigurationProperties;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ApplicationContext applicationContext;
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CacheManager cacheManager;
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AfterTransactionCommitExecutor afterCommitExecutor;
|
private AfterTransactionCommitExecutor afterCommitExecutor;
|
||||||
|
|
||||||
private static final ConfigurableConversionService conversionService = new DefaultConversionService();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Cacheable(value = "tenantConfiguration", key = "#configurationKeyName")
|
|
||||||
public <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(final String configurationKeyName,
|
|
||||||
final Class<T> propertyType) {
|
|
||||||
checkAccess(configurationKeyName);
|
|
||||||
|
|
||||||
final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName);
|
|
||||||
|
|
||||||
validateTenantConfigurationDataType(configurationKey, propertyType);
|
|
||||||
|
|
||||||
final TenantConfiguration tenantConfiguration = tenantConfigurationRepository
|
|
||||||
.findByKey(configurationKey.getKeyName());
|
|
||||||
|
|
||||||
return buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(
|
|
||||||
final String configurationKeyName) {
|
|
||||||
checkAccess(configurationKeyName);
|
|
||||||
|
|
||||||
final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName);
|
|
||||||
|
|
||||||
return getConfigurationValue(configurationKeyName, (Class<T>)configurationKey.getDataType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T getGlobalConfigurationValue(final String configurationKeyName, final Class<T> propertyType) {
|
|
||||||
checkAccess(configurationKeyName);
|
|
||||||
|
|
||||||
final TenantConfigurationKey key = tenantConfigurationProperties.fromKeyName(configurationKeyName);
|
|
||||||
|
|
||||||
if (!key.getDataType().isAssignableFrom(propertyType)) {
|
|
||||||
throw new TenantConfigurationValidatorException(String.format(
|
|
||||||
"Cannot parse the database value of type %s into the type %s.", key.getDataType(), propertyType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return conversionService.convert(key.getDefaultValue(), propertyType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkAccess(final String configurationKeyName) {
|
|
||||||
if (TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY
|
|
||||||
.equalsIgnoreCase(configurationKeyName)) {
|
|
||||||
final SystemSecurityContext systemSecurityContext =
|
|
||||||
SystemSecurityContextHolder.getInstance().getSystemSecurityContext();
|
|
||||||
if (!systemSecurityContext.isCurrentThreadSystemCode() &&
|
|
||||||
!systemSecurityContext.hasPermission(SpPermission.READ_GATEWAY_SEC_TOKEN)) {
|
|
||||||
throw new InsufficientPermissionException(
|
|
||||||
"Can't read gateway security token! " + SpPermission.READ_GATEWAY_SEC_TOKEN + " is required!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@CacheEvict(value = "tenantConfiguration", key = "#configurationKeyName")
|
@CacheEvict(value = "tenantConfiguration", key = "#configurationKeyName")
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -154,6 +96,85 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
|||||||
return addOrUpdateConfiguration0(configurations);
|
return addOrUpdateConfiguration0(configurations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(value = "tenantConfiguration", key = "#configurationKeyName")
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void deleteConfiguration(final String configurationKeyName) {
|
||||||
|
tenantConfigurationRepository.deleteByKey(configurationKeyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(
|
||||||
|
final String configurationKeyName) {
|
||||||
|
checkAccess(configurationKeyName);
|
||||||
|
|
||||||
|
final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName);
|
||||||
|
|
||||||
|
return getConfigurationValue(configurationKeyName, (Class<T>) configurationKey.getDataType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Cacheable(value = "tenantConfiguration", key = "#configurationKeyName")
|
||||||
|
public <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(final String configurationKeyName,
|
||||||
|
final Class<T> propertyType) {
|
||||||
|
checkAccess(configurationKeyName);
|
||||||
|
|
||||||
|
final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName);
|
||||||
|
|
||||||
|
validateTenantConfigurationDataType(configurationKey, propertyType);
|
||||||
|
|
||||||
|
final TenantConfiguration tenantConfiguration = tenantConfigurationRepository
|
||||||
|
.findByKey(configurationKey.getKeyName());
|
||||||
|
|
||||||
|
return buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getGlobalConfigurationValue(final String configurationKeyName, final Class<T> propertyType) {
|
||||||
|
checkAccess(configurationKeyName);
|
||||||
|
|
||||||
|
final TenantConfigurationKey key = tenantConfigurationProperties.fromKeyName(configurationKeyName);
|
||||||
|
|
||||||
|
if (!key.getDataType().isAssignableFrom(propertyType)) {
|
||||||
|
throw new TenantConfigurationValidatorException(String.format(
|
||||||
|
"Cannot parse the database value of type %s into the type %s.", key.getDataType(), propertyType));
|
||||||
|
}
|
||||||
|
|
||||||
|
return conversionService.convert(key.getDefaultValue(), propertyType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the data type of the tenant configuration. If it is possible to
|
||||||
|
* cast to the given data type.
|
||||||
|
*
|
||||||
|
* @param configurationKey the key
|
||||||
|
* @param propertyType the class
|
||||||
|
*/
|
||||||
|
private static <T> void validateTenantConfigurationDataType(final TenantConfigurationKey configurationKey,
|
||||||
|
final Class<T> propertyType) {
|
||||||
|
|
||||||
|
if (!configurationKey.getDataType().isAssignableFrom(propertyType)) {
|
||||||
|
throw new TenantConfigurationValidatorException(
|
||||||
|
String.format("Cannot parse the database value of type %s into the type %s.",
|
||||||
|
configurationKey.getDataType(), propertyType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAccess(final String configurationKeyName) {
|
||||||
|
if (TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY
|
||||||
|
.equalsIgnoreCase(configurationKeyName)) {
|
||||||
|
final SystemSecurityContext systemSecurityContext =
|
||||||
|
SystemSecurityContextHolder.getInstance().getSystemSecurityContext();
|
||||||
|
if (!systemSecurityContext.isCurrentThreadSystemCode() &&
|
||||||
|
!systemSecurityContext.hasPermission(SpPermission.READ_GATEWAY_SEC_TOKEN)) {
|
||||||
|
throw new InsufficientPermissionException(
|
||||||
|
"Can't read gateway security token! " + SpPermission.READ_GATEWAY_SEC_TOKEN + " is required!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private <T extends Serializable> Map<String, TenantConfigurationValue<T>> addOrUpdateConfiguration0(Map<String, T> configurations) {
|
private <T extends Serializable> Map<String, TenantConfigurationValue<T>> addOrUpdateConfiguration0(Map<String, T> configurations) {
|
||||||
List<JpaTenantConfiguration> configurationList = new ArrayList<>();
|
List<JpaTenantConfiguration> configurationList = new ArrayList<>();
|
||||||
configurations.forEach((configurationKeyName, value) -> {
|
configurations.forEach((configurationKeyName, value) -> {
|
||||||
@@ -187,9 +208,9 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
|||||||
JpaTenantConfiguration::getKey,
|
JpaTenantConfiguration::getKey,
|
||||||
updatedTenantConfiguration -> {
|
updatedTenantConfiguration -> {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked") final Class<T> clazzT = (Class<T>) configurations.get(updatedTenantConfiguration.getKey())
|
||||||
final Class<T> clazzT = (Class<T>) configurations.get(updatedTenantConfiguration.getKey()).getClass();
|
.getClass();
|
||||||
return TenantConfigurationValue.<T>builder().global(false)
|
return TenantConfigurationValue.<T> builder().global(false)
|
||||||
.createdBy(updatedTenantConfiguration.getCreatedBy())
|
.createdBy(updatedTenantConfiguration.getCreatedBy())
|
||||||
.createdAt(updatedTenantConfiguration.getCreatedAt())
|
.createdAt(updatedTenantConfiguration.getCreatedAt())
|
||||||
.lastModifiedAt(updatedTenantConfiguration.getLastModifiedAt())
|
.lastModifiedAt(updatedTenantConfiguration.getLastModifiedAt())
|
||||||
@@ -199,32 +220,6 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@CacheEvict(value = "tenantConfiguration", key = "#configurationKeyName")
|
|
||||||
@Transactional
|
|
||||||
@Retryable(include = {
|
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
|
||||||
public void deleteConfiguration(final String configurationKeyName) {
|
|
||||||
tenantConfigurationRepository.deleteByKey(configurationKeyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the data type of the tenant configuration. If it is possible to
|
|
||||||
* cast to the given data type.
|
|
||||||
*
|
|
||||||
* @param configurationKey the key
|
|
||||||
* @param propertyType the class
|
|
||||||
*/
|
|
||||||
private static <T> void validateTenantConfigurationDataType(final TenantConfigurationKey configurationKey,
|
|
||||||
final Class<T> propertyType) {
|
|
||||||
|
|
||||||
if (!configurationKey.getDataType().isAssignableFrom(propertyType)) {
|
|
||||||
throw new TenantConfigurationValidatorException(
|
|
||||||
String.format("Cannot parse the database value of type %s into the type %s.",
|
|
||||||
configurationKey.getDataType(), propertyType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends Serializable> TenantConfigurationValue<T> buildTenantConfigurationValueByKey(
|
private <T extends Serializable> TenantConfigurationValue<T> buildTenantConfigurationValueByKey(
|
||||||
final TenantConfigurationKey configurationKey, final Class<T> propertyType,
|
final TenantConfigurationKey configurationKey, final Class<T> propertyType,
|
||||||
final TenantConfiguration tenantConfiguration) {
|
final TenantConfiguration tenantConfiguration) {
|
||||||
@@ -247,14 +242,10 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
|||||||
/**
|
/**
|
||||||
* Asserts that the requested configuration value change is allowed. Throws
|
* Asserts that the requested configuration value change is allowed. Throws
|
||||||
* a {@link TenantConfigurationValueChangeNotAllowedException} otherwise.
|
* a {@link TenantConfigurationValueChangeNotAllowedException} otherwise.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key The configuration key.
|
||||||
* The configuration key.
|
* @param valueChange The configuration to be validated.
|
||||||
* @param valueChange
|
* @throws TenantConfigurationValueChangeNotAllowedException if the requested configuration change is not allowed.
|
||||||
* The configuration to be validated.
|
|
||||||
*
|
|
||||||
* @throws TenantConfigurationValueChangeNotAllowedException
|
|
||||||
* if the requested configuration change is not allowed.
|
|
||||||
*/
|
*/
|
||||||
private void assertValueChangeIsAllowed(final String key, final JpaTenantConfiguration valueChange) {
|
private void assertValueChangeIsAllowed(final String key, final JpaTenantConfiguration valueChange) {
|
||||||
assertMultiAssignmentsValueChange(key, valueChange);
|
assertMultiAssignmentsValueChange(key, valueChange);
|
||||||
@@ -280,7 +271,7 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
|||||||
}
|
}
|
||||||
if (MULTI_ASSIGNMENTS_ENABLED.equals(key) && Boolean.parseBoolean(valueChange.getValue())) {
|
if (MULTI_ASSIGNMENTS_ENABLED.equals(key) && Boolean.parseBoolean(valueChange.getValue())) {
|
||||||
JpaTenantConfiguration batchConfig = tenantConfigurationRepository.findByKey(BATCH_ASSIGNMENTS_ENABLED);
|
JpaTenantConfiguration batchConfig = tenantConfigurationRepository.findByKey(BATCH_ASSIGNMENTS_ENABLED);
|
||||||
if (batchConfig!=null && Boolean.parseBoolean(batchConfig.getValue())) {
|
if (batchConfig != null && Boolean.parseBoolean(batchConfig.getValue())) {
|
||||||
log.debug("The Multi-Assignments '{}' feature cannot be enabled as it contradicts with " +
|
log.debug("The Multi-Assignments '{}' feature cannot be enabled as it contradicts with " +
|
||||||
"The Batch-Assignments feature, which is already enabled .", key);
|
"The Batch-Assignments feature, which is already enabled .", key);
|
||||||
throw new TenantConfigurationValueChangeNotAllowedException();
|
throw new TenantConfigurationValueChangeNotAllowedException();
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Management service for statistics of a single tenant.
|
* Management service for statistics of a single tenant.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Validated
|
@Validated
|
||||||
public class JpaTenantStatsManagement implements TenantStatsManagement {
|
public class JpaTenantStatsManagement implements TenantStatsManagement {
|
||||||
|
|||||||
@@ -44,27 +44,18 @@ import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
|||||||
/**
|
/**
|
||||||
* AbstractDsAssignmentStrategy for offline assignments, i.e. not managed by
|
* AbstractDsAssignmentStrategy for offline assignments, i.e. not managed by
|
||||||
* hawkBit.
|
* hawkBit.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||||
|
|
||||||
OfflineDsAssignmentStrategy(final TargetRepository targetRepository,
|
OfflineDsAssignmentStrategy(final TargetRepository targetRepository,
|
||||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||||
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties) {
|
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties) {
|
||||||
super(targetRepository, afterCommit, eventPublisherHolder, actionRepository, actionStatusRepository,
|
super(targetRepository, afterCommit, eventPublisherHolder, actionRepository, actionStatusRepository,
|
||||||
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig, repositoryProperties);
|
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig, repositoryProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
|
||||||
targets.forEach(target -> {
|
|
||||||
target.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
|
||||||
sendTargetUpdatedEvent(target);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
||||||
final Function<List<String>, List<JpaTarget>> mapper;
|
final Function<List<String>, List<JpaTarget>> mapper;
|
||||||
@@ -80,13 +71,11 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
public void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
||||||
return Collections.emptySet();
|
targets.forEach(target -> {
|
||||||
}
|
target.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
||||||
|
sendTargetUpdatedEvent(target);
|
||||||
@Override
|
});
|
||||||
public void closeActiveActions(final List<List<Long>> targetIds) {
|
|
||||||
// Not supported by offline case
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,7 +83,8 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
final JpaDistributionSet set, final List<List<Long>> targetIds, final String currentUser) {
|
final JpaDistributionSet set, final List<List<Long>> targetIds, final String currentUser) {
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
targetIds.forEach(targetIdsChunk -> {
|
targetIds.forEach(targetIdsChunk -> {
|
||||||
if (targetRepository.count(AccessController.Operation.UPDATE, targetRepository.byIdsSpec(targetIdsChunk)) != targetIdsChunk.size()) {
|
if (targetRepository.count(AccessController.Operation.UPDATE,
|
||||||
|
targetRepository.byIdsSpec(targetIdsChunk)) != targetIdsChunk.size()) {
|
||||||
throw new InsufficientPermissionException("No update access to all targets!");
|
throw new InsufficientPermissionException("No update access to all targets!");
|
||||||
}
|
}
|
||||||
targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus(
|
targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus(
|
||||||
@@ -116,6 +106,26 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeActiveActions(final List<List<Long>> targetIds) {
|
||||||
|
// Not supported by offline case
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult) {
|
||||||
|
// no need to send deployment events in the offline case
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
||||||
|
// no need to send deployment events in the offline case
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
||||||
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
||||||
@@ -135,14 +145,4 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult) {
|
|
||||||
// no need to send deployment events in the offline case
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
|
||||||
// no need to send deployment events in the offline case
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,46 +47,18 @@ import org.springframework.util.CollectionUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* AbstractDsAssignmentStrategy for online assignments, i.e. managed by hawkBit.
|
* AbstractDsAssignmentStrategy for online assignments, i.e. managed by hawkBit.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||||
|
|
||||||
OnlineDsAssignmentStrategy(final TargetRepository targetRepository,
|
OnlineDsAssignmentStrategy(final TargetRepository targetRepository,
|
||||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||||
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties) {
|
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties) {
|
||||||
super(targetRepository, afterCommit, eventPublisherHolder, actionRepository, actionStatusRepository,
|
super(targetRepository, afterCommit, eventPublisherHolder, actionRepository, actionStatusRepository,
|
||||||
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig, repositoryProperties);
|
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig, repositoryProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
|
||||||
targets.forEach(target -> {
|
|
||||||
target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
|
||||||
sendTargetUpdatedEvent(target);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult) {
|
|
||||||
if (isMultiAssignmentsEnabled()) {
|
|
||||||
sendDeploymentEvents(Collections.singletonList(assignmentResult));
|
|
||||||
} else {
|
|
||||||
sendDistributionSetAssignedEvent(assignmentResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
|
||||||
if (isMultiAssignmentsEnabled()) {
|
|
||||||
sendDeploymentEvent(assignmentResults.stream().flatMap(result -> result.getAssignedEntity().stream())
|
|
||||||
.collect(Collectors.toList()));
|
|
||||||
} else {
|
|
||||||
assignmentResults.forEach(this::sendDistributionSetAssignedEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendDeploymentEvents(final long distributionSetId, final List<Action> actions) {
|
public void sendDeploymentEvents(final long distributionSetId, final List<Action> actions) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
if (isMultiAssignmentsEnabled()) {
|
||||||
sendDeploymentEvent(actions);
|
sendDeploymentEvent(actions);
|
||||||
@@ -114,14 +86,11 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
public void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
||||||
return targetIds.stream().map(this::overrideObsoleteUpdateActions).flatMap(Collection::stream)
|
targets.forEach(target -> {
|
||||||
.collect(Collectors.toSet());
|
target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||||
}
|
sendTargetUpdatedEvent(target);
|
||||||
|
});
|
||||||
@Override
|
|
||||||
public void closeActiveActions(final List<List<Long>> targetIds) {
|
|
||||||
targetIds.forEach(this::closeObsoleteUpdateActions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -129,7 +98,8 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
final String currentUser) {
|
final String currentUser) {
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
targetIds.forEach(targetIdsChunk -> {
|
targetIds.forEach(targetIdsChunk -> {
|
||||||
if (targetRepository.count(AccessController.Operation.UPDATE, targetRepository.byIdsSpec(targetIdsChunk)) != targetIdsChunk.size()) {
|
if (targetRepository.count(AccessController.Operation.UPDATE,
|
||||||
|
targetRepository.byIdsSpec(targetIdsChunk)) != targetIdsChunk.size()) {
|
||||||
throw new InsufficientPermissionException("No update access to all targets!");
|
throw new InsufficientPermissionException("No update access to all targets!");
|
||||||
}
|
}
|
||||||
targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
||||||
@@ -149,6 +119,36 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
||||||
|
return targetIds.stream().map(this::overrideObsoleteUpdateActions).flatMap(Collection::stream)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeActiveActions(final List<List<Long>> targetIds) {
|
||||||
|
targetIds.forEach(this::closeObsoleteUpdateActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult) {
|
||||||
|
if (isMultiAssignmentsEnabled()) {
|
||||||
|
sendDeploymentEvents(Collections.singletonList(assignmentResult));
|
||||||
|
} else {
|
||||||
|
sendDistributionSetAssignedEvent(assignmentResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
||||||
|
if (isMultiAssignmentsEnabled()) {
|
||||||
|
sendDeploymentEvent(assignmentResults.stream().flatMap(result -> result.getAssignedEntity().stream())
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
} else {
|
||||||
|
assignmentResults.forEach(this::sendDistributionSetAssignedEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
||||||
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
||||||
@@ -187,6 +187,20 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Stream<Action> filterCancellations(final List<Action> actions) {
|
||||||
|
return actions.stream().filter(action -> {
|
||||||
|
final Status actionStatus = action.getStatus();
|
||||||
|
return Status.CANCELING != actionStatus && Status.CANCELED != actionStatus;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Action> getActionsWithoutCancellations(final List<Action> actions) {
|
||||||
|
if (actions == null || actions.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return filterCancellations(actions).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
private void sendMultiActionCancelEvent(final Action action) {
|
private void sendMultiActionCancelEvent(final Action action) {
|
||||||
sendMultiActionCancelEvent(action.getTenant(), Collections.singletonList(action));
|
sendMultiActionCancelEvent(action.getTenant(), Collections.singletonList(action));
|
||||||
}
|
}
|
||||||
@@ -224,10 +238,8 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
* Helper to fire a {@link MultiActionCancelEvent}. This method may only be
|
* Helper to fire a {@link MultiActionCancelEvent}. This method may only be
|
||||||
* called if the Multi-Assignments feature is enabled.
|
* called if the Multi-Assignments feature is enabled.
|
||||||
*
|
*
|
||||||
* @param tenant
|
* @param tenant the event is scoped to
|
||||||
* the event is scoped to
|
* @param actions assigned to the targets
|
||||||
* @param actions
|
|
||||||
* assigned to the targets
|
|
||||||
*/
|
*/
|
||||||
private void sendMultiActionCancelEvent(final String tenant, final List<Action> actions) {
|
private void sendMultiActionCancelEvent(final String tenant, final List<Action> actions) {
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
||||||
@@ -238,28 +250,12 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
* Helper to fire a {@link MultiActionAssignEvent}. This method may only be
|
* Helper to fire a {@link MultiActionAssignEvent}. This method may only be
|
||||||
* called if the Multi-Assignments feature is enabled.
|
* called if the Multi-Assignments feature is enabled.
|
||||||
*
|
*
|
||||||
* @param tenant
|
* @param tenant the event is scoped to
|
||||||
* the event is scoped to
|
* @param actions assigned to the targets
|
||||||
* @param actions
|
|
||||||
* assigned to the targets
|
|
||||||
*/
|
*/
|
||||||
private void sendMultiActionAssignEvent(final String tenant, final List<Action> actions) {
|
private void sendMultiActionAssignEvent(final String tenant, final List<Action> actions) {
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
||||||
.publishEvent(new MultiActionAssignEvent(tenant, eventPublisherHolder.getApplicationId(), actions)));
|
.publishEvent(new MultiActionAssignEvent(tenant, eventPublisherHolder.getApplicationId(), actions)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<Action> filterCancellations(final List<Action> actions) {
|
|
||||||
return actions.stream().filter(action -> {
|
|
||||||
final Status actionStatus = action.getStatus();
|
|
||||||
return Status.CANCELING != actionStatus && Status.CANCELED != actionStatus;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Action> getActionsWithoutCancellations(final List<Action> actions) {
|
|
||||||
if (actions == null || actions.isEmpty()) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return filterCancellations(actions).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,15 +30,14 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holder of the base attributes common to all entities.
|
* Holder of the base attributes common to all entities.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
@Access(AccessType.FIELD)
|
@Access(AccessType.FIELD)
|
||||||
@EntityListeners({ AuditingEntityListener.class, EntityPropertyChangeListener.class, EntityInterceptorListener.class })
|
@EntityListeners({ AuditingEntityListener.class, EntityPropertyChangeListener.class, EntityInterceptorListener.class })
|
||||||
public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
protected static final int USERNAME_FIELD_LENGTH = 64;
|
|
||||||
|
|
||||||
|
protected static final int USERNAME_FIELD_LENGTH = 64;
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id")
|
@Column(name = "id")
|
||||||
@@ -88,6 +87,34 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
|||||||
return lastModifiedBy;
|
return lastModifiedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LastModifiedBy
|
||||||
|
public void setLastModifiedBy(final String lastModifiedBy) {
|
||||||
|
if (isController()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastModifiedBy = lastModifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOptLockRevision() {
|
||||||
|
return optLockRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOptLockRevision(final int optLockRevision) {
|
||||||
|
this.optLockRevision = optLockRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
@LastModifiedDate
|
||||||
|
public void setLastModifiedAt(final long lastModifiedAt) {
|
||||||
|
|
||||||
|
if (isController()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastModifiedAt = lastModifiedAt;
|
||||||
|
}
|
||||||
|
|
||||||
@CreatedBy
|
@CreatedBy
|
||||||
public void setCreatedBy(final String createdBy) {
|
public void setCreatedBy(final String createdBy) {
|
||||||
if (isController()) {
|
if (isController()) {
|
||||||
@@ -115,52 +142,11 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@LastModifiedDate
|
|
||||||
public void setLastModifiedAt(final long lastModifiedAt) {
|
|
||||||
|
|
||||||
if (isController()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastModifiedAt = lastModifiedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LastModifiedBy
|
|
||||||
public void setLastModifiedBy(final String lastModifiedBy) {
|
|
||||||
if (isController()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastModifiedBy = lastModifiedBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isController() {
|
|
||||||
return SecurityContextHolder.getContext().getAuthentication() != null
|
|
||||||
&& SecurityContextHolder.getContext().getAuthentication()
|
|
||||||
.getDetails() instanceof TenantAwareAuthenticationDetails
|
|
||||||
&& ((TenantAwareAuthenticationDetails) SecurityContextHolder.getContext().getAuthentication()
|
|
||||||
.getDetails()).isController();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOptLockRevision() {
|
|
||||||
return optLockRevision;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOptLockRevision(final int optLockRevision) {
|
|
||||||
this.optLockRevision = optLockRevision;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.getClass().getSimpleName() + " [id=" + id + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(final Long id) {
|
public void setId(final Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
@@ -169,7 +155,7 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
|||||||
* Defined equals/hashcode strategy for the repository in general is that an
|
* Defined equals/hashcode strategy for the repository in general is that an
|
||||||
* entity is equal if it has the same {@link #getId()} and
|
* entity is equal if it has the same {@link #getId()} and
|
||||||
* {@link #getOptLockRevision()} and class.
|
* {@link #getOptLockRevision()} and class.
|
||||||
*
|
*
|
||||||
* @see java.lang.Object#hashCode()
|
* @see java.lang.Object#hashCode()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -188,7 +174,7 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
|||||||
* Defined equals/hashcode strategy for the repository in general is that an
|
* Defined equals/hashcode strategy for the repository in general is that an
|
||||||
* entity is equal if it has the same {@link #getId()} and
|
* entity is equal if it has the same {@link #getId()} and
|
||||||
* {@link #getOptLockRevision()} and class.
|
* {@link #getOptLockRevision()} and class.
|
||||||
*
|
*
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -213,4 +199,17 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
|||||||
return optLockRevision == other.optLockRevision;
|
return optLockRevision == other.optLockRevision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getClass().getSimpleName() + " [id=" + id + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isController() {
|
||||||
|
return SecurityContextHolder.getContext().getAuthentication() != null
|
||||||
|
&& SecurityContextHolder.getContext().getAuthentication()
|
||||||
|
.getDetails() instanceof TenantAwareAuthenticationDetails
|
||||||
|
&& ((TenantAwareAuthenticationDetails) SecurityContextHolder.getContext().getAuthentication()
|
||||||
|
.getDetails()).isController();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import org.eclipse.hawkbit.repository.model.MetaData;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta data for entities.
|
* Meta data for entities.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public abstract class AbstractJpaMetaData implements MetaData {
|
public abstract class AbstractJpaMetaData implements MetaData {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@@ -66,6 +66,11 @@ public abstract class AbstractJpaMetaData implements MetaData {
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object o) {
|
public boolean equals(final Object o) {
|
||||||
if (this == o)
|
if (this == o)
|
||||||
@@ -75,9 +80,4 @@ public abstract class AbstractJpaMetaData implements MetaData {
|
|||||||
final AbstractJpaMetaData that = (AbstractJpaMetaData) o;
|
final AbstractJpaMetaData that = (AbstractJpaMetaData) o;
|
||||||
return Objects.equals(key, that.key) && Objects.equals(value, that.value);
|
return Objects.equals(key, that.key) && Objects.equals(value, that.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.model;
|
package org.eclipse.hawkbit.repository.jpa.model;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.MappedSuperclass;
|
import jakarta.persistence.MappedSuperclass;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@@ -17,8 +19,6 @@ import jakarta.validation.constraints.Size;
|
|||||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link TenantAwareBaseEntity} extension for all entities that are named in
|
* {@link TenantAwareBaseEntity} extension for all entities that are named in
|
||||||
* addition to their technical ID.
|
* addition to their technical ID.
|
||||||
@@ -51,10 +51,8 @@ public abstract class AbstractJpaNamedEntity extends AbstractJpaTenantAwareBaseE
|
|||||||
/**
|
/**
|
||||||
* Parameterized constructor.
|
* Parameterized constructor.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name of the {@link NamedEntity}
|
||||||
* of the {@link NamedEntity}
|
* @param description of the {@link NamedEntity}
|
||||||
* @param description
|
|
||||||
* of the {@link NamedEntity}
|
|
||||||
*/
|
*/
|
||||||
AbstractJpaNamedEntity(final String name, final String description) {
|
AbstractJpaNamedEntity(final String name, final String description) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -71,11 +69,11 @@ public abstract class AbstractJpaNamedEntity extends AbstractJpaTenantAwareBaseE
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDescription(final String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(final String name) {
|
public void setName(final String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension for {@link NamedEntity} that are versioned.
|
* Extension for {@link NamedEntity} that are versioned.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
public abstract class AbstractJpaNamedVersionedEntity extends AbstractJpaNamedEntity implements NamedVersionedEntity {
|
public abstract class AbstractJpaNamedVersionedEntity extends AbstractJpaNamedEntity implements NamedVersionedEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Column(name = "version", nullable = false, length = NamedVersionedEntity.VERSION_MAX_SIZE)
|
@Column(name = "version", nullable = false, length = NamedVersionedEntity.VERSION_MAX_SIZE)
|
||||||
@@ -36,10 +36,8 @@ public abstract class AbstractJpaNamedVersionedEntity extends AbstractJpaNamedEn
|
|||||||
/**
|
/**
|
||||||
* parameterized constructor.
|
* parameterized constructor.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name of the entity
|
||||||
* of the entity
|
* @param version of the entity
|
||||||
* @param version
|
|
||||||
* of the entity
|
|
||||||
* @param description
|
* @param description
|
||||||
*/
|
*/
|
||||||
AbstractJpaNamedVersionedEntity(final String name, final String version, final String description) {
|
AbstractJpaNamedVersionedEntity(final String name, final String version, final String description) {
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ import org.eclipse.persistence.annotations.TenantDiscriminatorColumn;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holder of the base attributes common to all tenant aware entities.
|
* Holder of the base attributes common to all tenant aware entities.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
@TenantDiscriminatorColumn(name = "tenant", length = 40)
|
@TenantDiscriminatorColumn(name = "tenant", length = 40)
|
||||||
@Multitenant(MultitenantType.SINGLE_TABLE)
|
@Multitenant(MultitenantType.SINGLE_TABLE)
|
||||||
public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEntity implements TenantAwareBaseEntity {
|
public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEntity implements TenantAwareBaseEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Column(name = "tenant", nullable = false, insertable = false, updatable = false, length = 40)
|
@Column(name = "tenant", nullable = false, insertable = false, updatable = false, length = 40)
|
||||||
@@ -45,24 +45,6 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
|
|||||||
// Default constructor needed for JPA entities.
|
// Default constructor needed for JPA entities.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* PrePersist listener method for all {@link TenantAwareBaseEntity}
|
|
||||||
* entities.
|
|
||||||
*/
|
|
||||||
@PrePersist
|
|
||||||
void prePersist() {
|
|
||||||
// before persisting the entity check the current ID of the tenant by
|
|
||||||
// using the TenantAware
|
|
||||||
// service
|
|
||||||
final String currentTenant = SystemManagementHolder.getInstance().currentTenant();
|
|
||||||
if (currentTenant == null) {
|
|
||||||
throw new TenantNotExistException("Tenant "
|
|
||||||
+ TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant()
|
|
||||||
+ " does not exists, cannot create entity " + this.getClass() + " with id " + super.getId());
|
|
||||||
}
|
|
||||||
setTenant(currentTenant.toUpperCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTenant() {
|
public String getTenant() {
|
||||||
return tenant;
|
return tenant;
|
||||||
@@ -72,17 +54,12 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
|
|||||||
this.tenant = tenant;
|
this.tenant = tenant;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "BaseEntity [id=" + super.getId() + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tenant aware entities extend the equals/hashcode strategy with the tenant
|
* Tenant aware entities extend the equals/hashcode strategy with the tenant
|
||||||
* name. That would allow for instance in a multi-schema based data
|
* name. That would allow for instance in a multi-schema based data
|
||||||
* separation setup to have the same primary key for different entities of
|
* separation setup to have the same primary key for different entities of
|
||||||
* different tenants.
|
* different tenants.
|
||||||
*
|
*
|
||||||
* @see org.eclipse.hawkbit.repository.model.BaseEntity#hashCode()
|
* @see org.eclipse.hawkbit.repository.model.BaseEntity#hashCode()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -98,7 +75,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
|
|||||||
* name. That would allow for instance in a multi-schema based data
|
* name. That would allow for instance in a multi-schema based data
|
||||||
* separation setup to have the same primary key for different entities of
|
* separation setup to have the same primary key for different entities of
|
||||||
* different tenants.
|
* different tenants.
|
||||||
*
|
*
|
||||||
* @see org.eclipse.hawkbit.repository.model.BaseEntity#equals(java.lang.Object)
|
* @see org.eclipse.hawkbit.repository.model.BaseEntity#equals(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -119,4 +96,27 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "BaseEntity [id=" + super.getId() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PrePersist listener method for all {@link TenantAwareBaseEntity}
|
||||||
|
* entities.
|
||||||
|
*/
|
||||||
|
@PrePersist
|
||||||
|
void prePersist() {
|
||||||
|
// before persisting the entity check the current ID of the tenant by
|
||||||
|
// using the TenantAware
|
||||||
|
// service
|
||||||
|
final String currentTenant = SystemManagementHolder.getInstance().currentTenant();
|
||||||
|
if (currentTenant == null) {
|
||||||
|
throw new TenantNotExistException("Tenant "
|
||||||
|
+ TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant()
|
||||||
|
+ " does not exists, cannot create entity " + this.getClass() + " with id " + super.getId());
|
||||||
|
}
|
||||||
|
setTenant(currentTenant.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.model;
|
package org.eclipse.hawkbit.repository.jpa.model;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
import java.io.Serial;
|
||||||
import org.eclipse.hawkbit.repository.model.Type;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.MappedSuperclass;
|
import jakarta.persistence.MappedSuperclass;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
import java.io.Serial;
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link TenantAwareBaseEntity} extension for all entities that are named in
|
* {@link TenantAwareBaseEntity} extension for all entities that are named in
|
||||||
@@ -49,10 +50,8 @@ public abstract class AbstractJpaTypeEntity extends AbstractJpaNamedEntity imple
|
|||||||
/**
|
/**
|
||||||
* Parameterized constructor.
|
* Parameterized constructor.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key of the {@link Type}
|
||||||
* of the {@link Type}
|
* @param colour of the {@link Type}
|
||||||
* @param colour
|
|
||||||
* of the {@link Type}
|
|
||||||
*/
|
*/
|
||||||
AbstractJpaTypeEntity(final String name, final String description, final String key, final String colour) {
|
AbstractJpaTypeEntity(final String name, final String description, final String key, final String colour) {
|
||||||
super(name, description);
|
super(name, description);
|
||||||
@@ -70,11 +69,11 @@ public abstract class AbstractJpaTypeEntity extends AbstractJpaNamedEntity imple
|
|||||||
return colour;
|
return colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKey(final String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColour(final String colour) {
|
public void setColour(final String colour) {
|
||||||
this.colour = colour;
|
this.colour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setKey(final String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ import org.eclipse.persistence.annotations.CascadeOnDelete;
|
|||||||
/**
|
/**
|
||||||
* Relation element between a {@link DistributionSetType} and its
|
* Relation element between a {@link DistributionSetType} and its
|
||||||
* {@link SoftwareModuleType} elements.
|
* {@link SoftwareModuleType} elements.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_ds_type_element")
|
@Table(name = "sp_ds_type_element")
|
||||||
public class DistributionSetTypeElement implements Serializable {
|
public class DistributionSetTypeElement implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@EmbeddedId
|
@EmbeddedId
|
||||||
@@ -62,13 +62,10 @@ public class DistributionSetTypeElement implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* Standard constructor.
|
* Standard constructor.
|
||||||
*
|
*
|
||||||
* @param dsType
|
* @param dsType of the element
|
||||||
* of the element
|
* @param smType of the element
|
||||||
* @param smType
|
* @param mandatory to <code>true</code> if the {@link SoftwareModuleType} if
|
||||||
* of the element
|
* mandatory element in the {@link DistributionSet}.
|
||||||
* @param mandatory
|
|
||||||
* to <code>true</code> if the {@link SoftwareModuleType} if
|
|
||||||
* mandatory element in the {@link DistributionSet}.
|
|
||||||
*/
|
*/
|
||||||
DistributionSetTypeElement(final JpaDistributionSetType dsType, final JpaSoftwareModuleType smType,
|
DistributionSetTypeElement(final JpaDistributionSetType dsType, final JpaSoftwareModuleType smType,
|
||||||
final boolean mandatory) {
|
final boolean mandatory) {
|
||||||
@@ -78,15 +75,15 @@ public class DistributionSetTypeElement implements Serializable {
|
|||||||
this.mandatory = mandatory;
|
this.mandatory = mandatory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMandatory() {
|
||||||
|
return mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
DistributionSetTypeElement setMandatory(final boolean mandatory) {
|
DistributionSetTypeElement setMandatory(final boolean mandatory) {
|
||||||
this.mandatory = mandatory;
|
this.mandatory = mandatory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMandatory() {
|
|
||||||
return mandatory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DistributionSetType getDsType() {
|
public DistributionSetType getDsType() {
|
||||||
return dsType;
|
return dsType;
|
||||||
}
|
}
|
||||||
@@ -99,11 +96,6 @@ public class DistributionSetTypeElement implements Serializable {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "DistributionSetTypeElement [mandatory=" + mandatory + ", dsType=" + dsType + ", smType=" + smType + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
@@ -134,4 +126,9 @@ public class DistributionSetTypeElement implements Serializable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DistributionSetTypeElement [mandatory=" + mandatory + ", dsType=" + dsType + ", smType=" + smType + "]";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import jakarta.persistence.Embeddable;
|
|||||||
*/
|
*/
|
||||||
@Embeddable
|
@Embeddable
|
||||||
public class DistributionSetTypeElementCompositeKey implements Serializable {
|
public class DistributionSetTypeElementCompositeKey implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Column(name = "distribution_set_type", nullable = false, updatable = false)
|
@Column(name = "distribution_set_type", nullable = false, updatable = false)
|
||||||
@@ -36,10 +37,8 @@ public class DistributionSetTypeElementCompositeKey implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param dsType
|
* @param dsType in the key
|
||||||
* in the key
|
* @param smType in the key
|
||||||
* @param smType
|
|
||||||
* in the key
|
|
||||||
*/
|
*/
|
||||||
DistributionSetTypeElementCompositeKey(final JpaDistributionSetType dsType, final JpaSoftwareModuleType smType) {
|
DistributionSetTypeElementCompositeKey(final JpaDistributionSetType dsType, final JpaSoftwareModuleType smType) {
|
||||||
this.dsType = dsType.getId();
|
this.dsType = dsType.getId();
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import java.io.Serializable;
|
|||||||
/**
|
/**
|
||||||
* The DistributionSet Metadata composite key which contains the meta data key
|
* The DistributionSet Metadata composite key which contains the meta data key
|
||||||
* and the ID of the DistributionSet itself.
|
* and the ID of the DistributionSet itself.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public final class DsMetadataCompositeKey implements Serializable {
|
public final class DsMetadataCompositeKey implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
@@ -28,10 +28,8 @@ public final class DsMetadataCompositeKey implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param distributionSet
|
* @param distributionSet the distribution set for this meta data
|
||||||
* the distribution set for this meta data
|
* @param key the key of the meta data
|
||||||
* @param key
|
|
||||||
* the key of the meta data
|
|
||||||
*/
|
*/
|
||||||
public DsMetadataCompositeKey(final Long distributionSet, final String key) {
|
public DsMetadataCompositeKey(final Long distributionSet, final String key) {
|
||||||
this.distributionSet = distributionSet;
|
this.distributionSet = distributionSet;
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ public class EntityInterceptorListener {
|
|||||||
/**
|
/**
|
||||||
* Callback for lifecyle event <i>pre persist</i>.
|
* Callback for lifecyle event <i>pre persist</i>.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the JPA entity which this listener is associated with
|
||||||
* the JPA entity which this listener is associated with
|
|
||||||
*/
|
*/
|
||||||
@PrePersist
|
@PrePersist
|
||||||
public void prePersist(final Object entity) {
|
public void prePersist(final Object entity) {
|
||||||
@@ -42,8 +41,7 @@ public class EntityInterceptorListener {
|
|||||||
/**
|
/**
|
||||||
* Callback for lifecyle event <i>post persist</i>.
|
* Callback for lifecyle event <i>post persist</i>.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the JPA entity which this listener is associated with
|
||||||
* the JPA entity which this listener is associated with
|
|
||||||
*/
|
*/
|
||||||
@PostPersist
|
@PostPersist
|
||||||
public void postPersist(final Object entity) {
|
public void postPersist(final Object entity) {
|
||||||
@@ -53,8 +51,7 @@ public class EntityInterceptorListener {
|
|||||||
/**
|
/**
|
||||||
* Callback for lifecyle event <i>post remove</i>.
|
* Callback for lifecyle event <i>post remove</i>.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the JPA entity which this listener is associated with
|
||||||
* the JPA entity which this listener is associated with
|
|
||||||
*/
|
*/
|
||||||
@PostRemove
|
@PostRemove
|
||||||
public void postRemove(final Object entity) {
|
public void postRemove(final Object entity) {
|
||||||
@@ -64,8 +61,7 @@ public class EntityInterceptorListener {
|
|||||||
/**
|
/**
|
||||||
* Callback for lifecyle event <i>pre remove</i>.
|
* Callback for lifecyle event <i>pre remove</i>.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the JPA entity which this listener is associated with
|
||||||
* the JPA entity which this listener is associated with
|
|
||||||
*/
|
*/
|
||||||
@PreRemove
|
@PreRemove
|
||||||
public void preRemove(final Object entity) {
|
public void preRemove(final Object entity) {
|
||||||
@@ -75,8 +71,7 @@ public class EntityInterceptorListener {
|
|||||||
/**
|
/**
|
||||||
* Callback for lifecyle event <i>post load</i>.
|
* Callback for lifecyle event <i>post load</i>.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the JPA entity which this listener is associated with
|
||||||
* the JPA entity which this listener is associated with
|
|
||||||
*/
|
*/
|
||||||
@PostLoad
|
@PostLoad
|
||||||
public void postLoad(final Object entity) {
|
public void postLoad(final Object entity) {
|
||||||
@@ -86,8 +81,7 @@ public class EntityInterceptorListener {
|
|||||||
/**
|
/**
|
||||||
* Callback for lifecyle event <i>pre update</i>.
|
* Callback for lifecyle event <i>pre update</i>.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the JPA entity which this listener is associated with
|
||||||
* the JPA entity which this listener is associated with
|
|
||||||
*/
|
*/
|
||||||
@PreUpdate
|
@PreUpdate
|
||||||
public void preUpdate(final Object entity) {
|
public void preUpdate(final Object entity) {
|
||||||
@@ -97,8 +91,7 @@ public class EntityInterceptorListener {
|
|||||||
/**
|
/**
|
||||||
* Callback for lifecyle event <i>post update</i>.
|
* Callback for lifecyle event <i>post update</i>.
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity the JPA entity which this listener is associated with
|
||||||
* the JPA entity which this listener is associated with
|
|
||||||
*/
|
*/
|
||||||
@PostUpdate
|
@PostUpdate
|
||||||
public void postUpdate(final Object entity) {
|
public void postUpdate(final Object entity) {
|
||||||
|
|||||||
@@ -17,10 +17,17 @@ import org.eclipse.persistence.queries.UpdateObjectQuery;
|
|||||||
/**
|
/**
|
||||||
* Listens to change in property values of an entity and calls the corresponding
|
* Listens to change in property values of an entity and calls the corresponding
|
||||||
* {@link EventAwareEntity}.
|
* {@link EventAwareEntity}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class EntityPropertyChangeListener extends DescriptorEventAdapter {
|
public class EntityPropertyChangeListener extends DescriptorEventAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postDelete(final DescriptorEvent event) {
|
||||||
|
final Object object = event.getObject();
|
||||||
|
if (isEventAwareEntity(object)) {
|
||||||
|
doNotifiy(() -> ((EventAwareEntity) object).fireDeleteEvent(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postInsert(final DescriptorEvent event) {
|
public void postInsert(final DescriptorEvent event) {
|
||||||
final Object object = event.getObject();
|
final Object object = event.getObject();
|
||||||
@@ -40,14 +47,6 @@ public class EntityPropertyChangeListener extends DescriptorEventAdapter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postDelete(final DescriptorEvent event) {
|
|
||||||
final Object object = event.getObject();
|
|
||||||
if (isEventAwareEntity(object)) {
|
|
||||||
doNotifiy(() -> ((EventAwareEntity) object).fireDeleteEvent(event));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isEventAwareEntity(final Object object) {
|
private static boolean isEventAwareEntity(final Object object) {
|
||||||
return object instanceof EventAwareEntity;
|
return object instanceof EventAwareEntity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,21 +22,21 @@ public interface EventAwareEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired for the Entity creation.
|
* Fired for the Entity creation.
|
||||||
*
|
*
|
||||||
* @param descriptorEvent
|
* @param descriptorEvent
|
||||||
*/
|
*/
|
||||||
void fireCreateEvent(DescriptorEvent descriptorEvent);
|
void fireCreateEvent(DescriptorEvent descriptorEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired for the Entity updation.
|
* Fired for the Entity updation.
|
||||||
*
|
*
|
||||||
* @param descriptorEvent
|
* @param descriptorEvent
|
||||||
*/
|
*/
|
||||||
void fireUpdateEvent(DescriptorEvent descriptorEvent);
|
void fireUpdateEvent(DescriptorEvent descriptorEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired for the Entity deletion.
|
* Fired for the Entity deletion.
|
||||||
*
|
*
|
||||||
* @param descriptorEvent
|
* @param descriptorEvent
|
||||||
*/
|
*/
|
||||||
void fireDeleteEvent(DescriptorEvent descriptorEvent);
|
void fireDeleteEvent(DescriptorEvent descriptorEvent);
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent;
|
|||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action, EventAwareEntity {
|
public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action, EventAwareEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
@@ -113,7 +114,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@ConversionValue(objectValue = "SCHEDULED", dataValue = "8"),
|
@ConversionValue(objectValue = "SCHEDULED", dataValue = "8"),
|
||||||
@ConversionValue(objectValue = "CANCEL_REJECTED", dataValue = "9"),
|
@ConversionValue(objectValue = "CANCEL_REJECTED", dataValue = "9"),
|
||||||
@ConversionValue(objectValue = "DOWNLOADED", dataValue = "10"),
|
@ConversionValue(objectValue = "DOWNLOADED", dataValue = "10"),
|
||||||
@ConversionValue(objectValue = "WAIT_FOR_CONFIRMATION", dataValue = "11")})
|
@ConversionValue(objectValue = "WAIT_FOR_CONFIRMATION", dataValue = "11") })
|
||||||
@Convert("status")
|
@Convert("status")
|
||||||
@NotNull
|
@NotNull
|
||||||
private Status status;
|
private Status status;
|
||||||
@@ -157,10 +158,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
this.distributionSet = (JpaDistributionSet) distributionSet;
|
this.distributionSet = (JpaDistributionSet) distributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setActive(final boolean active) {
|
|
||||||
this.active = active;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
return status;
|
return status;
|
||||||
@@ -175,8 +172,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setActionType(final ActionType actionType) {
|
public void setActive(final boolean active) {
|
||||||
this.actionType = actionType;
|
this.active = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -184,16 +181,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
return actionType;
|
return actionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ActionStatus> getActionStatus() {
|
public void setActionType(final ActionType actionType) {
|
||||||
if (actionStatus == null) {
|
this.actionType = actionType;
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(actionStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTarget(final Target target) {
|
|
||||||
this.target = (JpaTarget) target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,6 +190,10 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTarget(final Target target) {
|
||||||
|
this.target = (JpaTarget) target;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getForcedTime() {
|
public long getForcedTime() {
|
||||||
return forcedTime;
|
return forcedTime;
|
||||||
@@ -237,35 +230,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
this.rollout = (JpaRollout) rollout;
|
this.rollout = (JpaRollout) rollout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id="
|
|
||||||
+ getId() + ", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive()
|
|
||||||
+ ", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + ", status="
|
|
||||||
+ getStatus().name() + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
|
||||||
EventPublisherHolder.getInstance().getEventPublisher()
|
|
||||||
.publishEvent(new ActionCreatedEvent(this, BaseEntity.getIdOrNull(target),
|
|
||||||
BaseEntity.getIdOrNull(rollout), BaseEntity.getIdOrNull(rolloutGroup),
|
|
||||||
EventPublisherHolder.getInstance().getApplicationId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
|
||||||
EventPublisherHolder.getInstance().getEventPublisher()
|
|
||||||
.publishEvent(new ActionUpdatedEvent(this, BaseEntity.getIdOrNull(target),
|
|
||||||
BaseEntity.getIdOrNull(rollout), BaseEntity.getIdOrNull(rolloutGroup),
|
|
||||||
EventPublisherHolder.getInstance().getApplicationId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fireDeleteEvent(final DescriptorEvent descriptorEvent) {
|
|
||||||
// there is no action deletion
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMaintenanceWindowSchedule() {
|
public String getMaintenanceWindowSchedule() {
|
||||||
return maintenanceWindowSchedule;
|
return maintenanceWindowSchedule;
|
||||||
@@ -274,8 +238,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
/**
|
/**
|
||||||
* Sets the maintenance schedule.
|
* Sets the maintenance schedule.
|
||||||
*
|
*
|
||||||
* @param maintenanceWindowSchedule
|
* @param maintenanceWindowSchedule is a cron expression to be used for scheduling.
|
||||||
* is a cron expression to be used for scheduling.
|
|
||||||
*/
|
*/
|
||||||
public void setMaintenanceWindowSchedule(final String maintenanceWindowSchedule) {
|
public void setMaintenanceWindowSchedule(final String maintenanceWindowSchedule) {
|
||||||
this.maintenanceWindowSchedule = maintenanceWindowSchedule;
|
this.maintenanceWindowSchedule = maintenanceWindowSchedule;
|
||||||
@@ -289,9 +252,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
/**
|
/**
|
||||||
* Sets the maintenance window duration.
|
* Sets the maintenance window duration.
|
||||||
*
|
*
|
||||||
* @param maintenanceWindowDuration
|
* @param maintenanceWindowDuration is the duration of an available maintenance schedule in
|
||||||
* is the duration of an available maintenance schedule in
|
* HH:mm:ss format.
|
||||||
* HH:mm:ss format.
|
|
||||||
*/
|
*/
|
||||||
public void setMaintenanceWindowDuration(final String maintenanceWindowDuration) {
|
public void setMaintenanceWindowDuration(final String maintenanceWindowDuration) {
|
||||||
this.maintenanceWindowDuration = maintenanceWindowDuration;
|
this.maintenanceWindowDuration = maintenanceWindowDuration;
|
||||||
@@ -305,34 +267,45 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
/**
|
/**
|
||||||
* Sets the time zone to be used for maintenance window.
|
* Sets the time zone to be used for maintenance window.
|
||||||
*
|
*
|
||||||
* @param maintenanceWindowTimeZone
|
* @param maintenanceWindowTimeZone is the time zone specified as +/-hh:mm offset from UTC for
|
||||||
* is the time zone specified as +/-hh:mm offset from UTC for
|
* example +02:00 for CET summer time and +00:00 for UTC. The
|
||||||
* example +02:00 for CET summer time and +00:00 for UTC. The
|
* start time of a maintenance window calculated based on the
|
||||||
* start time of a maintenance window calculated based on the
|
* cron expression is relative to this time zone.
|
||||||
* cron expression is relative to this time zone.
|
|
||||||
*/
|
*/
|
||||||
public void setMaintenanceWindowTimeZone(final String maintenanceWindowTimeZone) {
|
public void setMaintenanceWindowTimeZone(final String maintenanceWindowTimeZone) {
|
||||||
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
|
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExternalRef() {
|
||||||
|
return externalRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExternalRef(final String externalRef) {
|
||||||
|
this.externalRef = externalRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInitiatedBy() {
|
||||||
|
return initiatedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitiatedBy(final String initiatedBy) {
|
||||||
|
this.initiatedBy = initiatedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Integer> getLastActionStatusCode() {
|
||||||
|
return Optional.ofNullable(lastActionStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ZonedDateTime> getMaintenanceWindowStartTime() {
|
public Optional<ZonedDateTime> getMaintenanceWindowStartTime() {
|
||||||
return MaintenanceScheduleHelper.getNextMaintenanceWindow(maintenanceWindowSchedule, maintenanceWindowDuration,
|
return MaintenanceScheduleHelper.getNextMaintenanceWindow(maintenanceWindowSchedule, maintenanceWindowDuration,
|
||||||
maintenanceWindowTimeZone);
|
maintenanceWindowTimeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the end time of next available or active maintenance window for
|
|
||||||
* the {@link Action} as {@link ZonedDateTime}. If a maintenance window is
|
|
||||||
* already active, the end time of currently active window is returned.
|
|
||||||
*
|
|
||||||
* @return the end time of window as { @link Optional<ZonedDateTime>}.
|
|
||||||
*/
|
|
||||||
private Optional<ZonedDateTime> getMaintenanceWindowEndTime() {
|
|
||||||
return getMaintenanceWindowStartTime()
|
|
||||||
.map(start -> start.plus(MaintenanceScheduleHelper.convertToISODuration(maintenanceWindowDuration)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasMaintenanceSchedule() {
|
public boolean hasMaintenanceSchedule() {
|
||||||
return this.maintenanceWindowSchedule != null;
|
return this.maintenanceWindowSchedule != null;
|
||||||
@@ -366,35 +339,60 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean isWaitingConfirmation() {
|
||||||
public void setExternalRef(final String externalRef) {
|
return status == Status.WAIT_FOR_CONFIRMATION;
|
||||||
this.externalRef = externalRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getExternalRef() {
|
|
||||||
return externalRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitiatedBy(final String initiatedBy) {
|
|
||||||
this.initiatedBy = initiatedBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getInitiatedBy() {
|
|
||||||
return initiatedBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Integer> getLastActionStatusCode() {
|
|
||||||
return Optional.ofNullable(lastActionStatusCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLastActionStatusCode(final Integer lastActionStatusCode) {
|
public void setLastActionStatusCode(final Integer lastActionStatusCode) {
|
||||||
this.lastActionStatusCode = lastActionStatusCode;
|
this.lastActionStatusCode = lastActionStatusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isWaitingConfirmation() {
|
public List<ActionStatus> getActionStatus() {
|
||||||
return status == Status.WAIT_FOR_CONFIRMATION;
|
if (actionStatus == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(actionStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id="
|
||||||
|
+ getId() + ", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive()
|
||||||
|
+ ", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + ", status="
|
||||||
|
+ getStatus().name() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||||
|
EventPublisherHolder.getInstance().getEventPublisher()
|
||||||
|
.publishEvent(new ActionCreatedEvent(this, BaseEntity.getIdOrNull(target),
|
||||||
|
BaseEntity.getIdOrNull(rollout), BaseEntity.getIdOrNull(rolloutGroup),
|
||||||
|
EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
||||||
|
EventPublisherHolder.getInstance().getEventPublisher()
|
||||||
|
.publishEvent(new ActionUpdatedEvent(this, BaseEntity.getIdOrNull(target),
|
||||||
|
BaseEntity.getIdOrNull(rollout), BaseEntity.getIdOrNull(rolloutGroup),
|
||||||
|
EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fireDeleteEvent(final DescriptorEvent descriptorEvent) {
|
||||||
|
// there is no action deletion
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the end time of next available or active maintenance window for
|
||||||
|
* the {@link Action} as {@link ZonedDateTime}. If a maintenance window is
|
||||||
|
* already active, the end time of currently active window is returned.
|
||||||
|
*
|
||||||
|
* @return the end time of window as { @link Optional<ZonedDateTime>}.
|
||||||
|
*/
|
||||||
|
private Optional<ZonedDateTime> getMaintenanceWindowEndTime() {
|
||||||
|
return getMaintenanceWindowStartTime()
|
||||||
|
.map(start -> start.plus(MaintenanceScheduleHelper.convertToISODuration(maintenanceWindowDuration)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
import jakarta.persistence.CollectionTable;
|
import jakarta.persistence.CollectionTable;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
@@ -50,6 +49,7 @@ import org.eclipse.persistence.annotations.ObjectTypeConverter;
|
|||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements ActionStatus {
|
public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements ActionStatus {
|
||||||
|
|
||||||
private static final int MESSAGE_ENTRY_LENGTH = 512;
|
private static final int MESSAGE_ENTRY_LENGTH = 512;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@@ -75,7 +75,7 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
@ConversionValue(objectValue = "SCHEDULED", dataValue = "8"),
|
@ConversionValue(objectValue = "SCHEDULED", dataValue = "8"),
|
||||||
@ConversionValue(objectValue = "CANCEL_REJECTED", dataValue = "9"),
|
@ConversionValue(objectValue = "CANCEL_REJECTED", dataValue = "9"),
|
||||||
@ConversionValue(objectValue = "DOWNLOADED", dataValue = "10"),
|
@ConversionValue(objectValue = "DOWNLOADED", dataValue = "10"),
|
||||||
@ConversionValue(objectValue = "WAIT_FOR_CONFIRMATION", dataValue = "11")})
|
@ConversionValue(objectValue = "WAIT_FOR_CONFIRMATION", dataValue = "11") })
|
||||||
@Convert("status")
|
@Convert("status")
|
||||||
@NotNull
|
@NotNull
|
||||||
private Status status;
|
private Status status;
|
||||||
@@ -89,16 +89,13 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
|
|
||||||
@Column(name = "code", nullable = true, updatable = false)
|
@Column(name = "code", nullable = true, updatable = false)
|
||||||
private Integer code;
|
private Integer code;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ActionStatus} object.
|
* Creates a new {@link ActionStatus} object.
|
||||||
*
|
*
|
||||||
* @param action
|
* @param action the action for this action status
|
||||||
* the action for this action status
|
* @param status the status for this action status
|
||||||
* @param status
|
* @param occurredAt the occurred timestamp
|
||||||
* the status for this action status
|
|
||||||
* @param occurredAt
|
|
||||||
* the occurred timestamp
|
|
||||||
*/
|
*/
|
||||||
public JpaActionStatus(final Action action, final Status status, final long occurredAt) {
|
public JpaActionStatus(final Action action, final Status status, final long occurredAt) {
|
||||||
this.action = (JpaAction) action;
|
this.action = (JpaAction) action;
|
||||||
@@ -109,14 +106,10 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
/**
|
/**
|
||||||
* Creates a new {@link ActionStatus} object.
|
* Creates a new {@link ActionStatus} object.
|
||||||
*
|
*
|
||||||
* @param action
|
* @param action the action for this action status
|
||||||
* the action for this action status
|
* @param status the status for this action status
|
||||||
* @param status
|
* @param occurredAt the occurred timestamp
|
||||||
* the status for this action status
|
* @param message the message which should be added to this action status
|
||||||
* @param occurredAt
|
|
||||||
* the occurred timestamp
|
|
||||||
* @param message
|
|
||||||
* the message which should be added to this action status
|
|
||||||
*/
|
*/
|
||||||
public JpaActionStatus(final JpaAction action, final Status status, final long occurredAt, final String message) {
|
public JpaActionStatus(final JpaAction action, final Status status, final long occurredAt, final String message) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
@@ -128,10 +121,8 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
/**
|
/**
|
||||||
* Creates a new {@link ActionStatus} object.
|
* Creates a new {@link ActionStatus} object.
|
||||||
*
|
*
|
||||||
* @param status
|
* @param status the status for this action status
|
||||||
* the status for this action status
|
* @param occurredAt the occurred timestamp
|
||||||
* @param occurredAt
|
|
||||||
* the occurred timestamp
|
|
||||||
*/
|
*/
|
||||||
public JpaActionStatus(final Status status, final long occurredAt) {
|
public JpaActionStatus(final Status status, final long occurredAt) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
@@ -154,36 +145,6 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
this.occurredAt = occurredAt;
|
this.occurredAt = occurredAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void addMessage(final String message) {
|
|
||||||
if (message != null) {
|
|
||||||
if (messages == null) {
|
|
||||||
messages = new ArrayList<>((message.length() / MESSAGE_ENTRY_LENGTH) + 1);
|
|
||||||
}
|
|
||||||
if (message.length() > MESSAGE_ENTRY_LENGTH) {
|
|
||||||
// split
|
|
||||||
for (int off = 0; off < message.length();) {
|
|
||||||
final int end = off + MESSAGE_ENTRY_LENGTH;
|
|
||||||
if (end < message.length()) {
|
|
||||||
messages.add(message.substring(off, end));
|
|
||||||
} else {
|
|
||||||
messages.add(message.substring(off));
|
|
||||||
}
|
|
||||||
off = end;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
messages.add(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getMessages() {
|
|
||||||
if (messages == null) {
|
|
||||||
messages = Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Action getAction() {
|
public Action getAction() {
|
||||||
return action;
|
return action;
|
||||||
@@ -209,4 +170,34 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
public void setCode(final Integer code) {
|
public void setCode(final Integer code) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void addMessage(final String message) {
|
||||||
|
if (message != null) {
|
||||||
|
if (messages == null) {
|
||||||
|
messages = new ArrayList<>((message.length() / MESSAGE_ENTRY_LENGTH) + 1);
|
||||||
|
}
|
||||||
|
if (message.length() > MESSAGE_ENTRY_LENGTH) {
|
||||||
|
// split
|
||||||
|
for (int off = 0; off < message.length(); ) {
|
||||||
|
final int end = off + MESSAGE_ENTRY_LENGTH;
|
||||||
|
if (end < message.length()) {
|
||||||
|
messages.add(message.substring(off, end));
|
||||||
|
} else {
|
||||||
|
messages.add(message.substring(off));
|
||||||
|
}
|
||||||
|
off = end;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messages.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getMessages() {
|
||||||
|
if (messages == null) {
|
||||||
|
messages = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(messages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of {@link Artifact}.
|
* JPA implementation of {@link Artifact}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
|
@Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
|
||||||
@Index(name = "sp_idx_artifact_02", columnList = "tenant,sha1_hash"),
|
@Index(name = "sp_idx_artifact_02", columnList = "tenant,sha1_hash"),
|
||||||
@@ -39,6 +38,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
|||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Artifact {
|
public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Artifact {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Column(name = "sha1_hash", length = 40, nullable = false, updatable = false)
|
@Column(name = "sha1_hash", length = 40, nullable = false, updatable = false)
|
||||||
@@ -74,12 +74,9 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
|||||||
/**
|
/**
|
||||||
* Constructs artifact.
|
* Constructs artifact.
|
||||||
*
|
*
|
||||||
* @param sha1Hash
|
* @param sha1Hash that is the link to the {@link AbstractDbArtifact} entity.
|
||||||
* that is the link to the {@link AbstractDbArtifact} entity.
|
* @param filename that is used by {@link AbstractDbArtifact} store.
|
||||||
* @param filename
|
* @param softwareModule of this artifact
|
||||||
* that is used by {@link AbstractDbArtifact} store.
|
|
||||||
* @param softwareModule
|
|
||||||
* of this artifact
|
|
||||||
*/
|
*/
|
||||||
public JpaArtifact(@NotEmpty final String sha1Hash, @NotNull final String filename,
|
public JpaArtifact(@NotEmpty final String sha1Hash, @NotNull final String filename,
|
||||||
final SoftwareModule softwareModule) {
|
final SoftwareModule softwareModule) {
|
||||||
@@ -89,6 +86,16 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
|||||||
this.softwareModule.addArtifact(this);
|
this.softwareModule.addArtifact(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SoftwareModule getSoftwareModule() {
|
||||||
|
return softwareModule;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMd5Hash() {
|
public String getMd5Hash() {
|
||||||
return md5Hash;
|
return md5Hash;
|
||||||
@@ -104,19 +111,10 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
|||||||
return sha256Hash;
|
return sha256Hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMd5Hash(final String md5Hash) {
|
|
||||||
this.md5Hash = md5Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSha1Hash(final String sha1Hash) {
|
|
||||||
this.sha1Hash = sha1Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSha256Hash(final String sha256Hash) {
|
public void setSha256Hash(final String sha256Hash) {
|
||||||
this.sha256Hash = sha256Hash;
|
this.sha256Hash = sha256Hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return size;
|
return size;
|
||||||
@@ -126,13 +124,11 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
|||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setSha1Hash(final String sha1Hash) {
|
||||||
public SoftwareModule getSoftwareModule() {
|
this.sha1Hash = sha1Hash;
|
||||||
return softwareModule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setMd5Hash(final String md5Hash) {
|
||||||
public String getFilename() {
|
this.md5Hash = md5Hash;
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.model;
|
package org.eclipse.hawkbit.repository.jpa.model;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
|
|
||||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
@@ -24,6 +19,11 @@ import jakarta.persistence.OneToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
|
||||||
|
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_target_conf_status")
|
@Table(name = "sp_target_conf_status")
|
||||||
public class JpaAutoConfirmationStatus extends AbstractJpaTenantAwareBaseEntity implements AutoConfirmationStatus {
|
public class JpaAutoConfirmationStatus extends AbstractJpaTenantAwareBaseEntity implements AutoConfirmationStatus {
|
||||||
@@ -81,11 +81,11 @@ public class JpaAutoConfirmationStatus extends AbstractJpaTenantAwareBaseEntity
|
|||||||
// https://docs.oracle.com/en/java/javase/17/text-blocks/index.html#normalization-of-line-terminators
|
// https://docs.oracle.com/en/java/javase/17/text-blocks/index.html#normalization-of-line-terminators
|
||||||
// nevertheless of the end of line of the file (\r\n, \n or \r) the result will contains \n
|
// nevertheless of the end of line of the file (\r\n, \n or \r) the result will contains \n
|
||||||
return """
|
return """
|
||||||
Assignment automatically confirmed by initiator '%s'.\040
|
Assignment automatically confirmed by initiator '%s'.\040
|
||||||
|
|
||||||
Auto confirmation activated by system user: '%s'\040
|
Auto confirmation activated by system user: '%s'\040
|
||||||
|
|
||||||
Remark: %s""".formatted(formattedInitiator, createdByRolloutsUser, remarkMessage);
|
Remark: %s""".formatted(formattedInitiator, createdByRolloutsUser, remarkMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ import org.springframework.context.ApplicationEvent;
|
|||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_distribution_set", uniqueConstraints = {
|
@Table(name = "sp_distribution_set", uniqueConstraints = {
|
||||||
@UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = {
|
@UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = {
|
||||||
@Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,complete"),
|
@Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,complete"),
|
||||||
@Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") })
|
@Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") })
|
||||||
@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"),
|
@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"),
|
||||||
@NamedAttributeNode("tags"), @NamedAttributeNode("type") })
|
@NamedAttributeNode("tags"), @NamedAttributeNode("type") })
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
@@ -90,7 +90,7 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
|||||||
@ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY)
|
@ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY)
|
||||||
@JoinTable(name = "sp_ds_module", joinColumns = {
|
@JoinTable(name = "sp_ds_module", joinColumns = {
|
||||||
@JoinColumn(name = "ds_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = {
|
@JoinColumn(name = "ds_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = {
|
||||||
@JoinColumn(name = "module_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) })
|
@JoinColumn(name = "module_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) })
|
||||||
private Set<SoftwareModule> modules;
|
private Set<SoftwareModule> modules;
|
||||||
|
|
||||||
@CascadeOnDelete
|
@CascadeOnDelete
|
||||||
@@ -284,18 +284,6 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
|||||||
EventPublisherHolder.getInstance().getApplicationId()));
|
EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkTypeCompatability(final SoftwareModule softwareModule) {
|
|
||||||
// we cannot allow that modules are added without a type defined
|
|
||||||
if (type == null) {
|
|
||||||
throw new DistributionSetTypeUndefinedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if it is allowed to such a module to this DS type
|
|
||||||
if (!type.containsModuleType(softwareModule.getType())) {
|
|
||||||
throw new UnsupportedSoftwareModuleForThisDistributionSetException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void publishEventWithEventPublisher(final ApplicationEvent event) {
|
private static void publishEventWithEventPublisher(final ApplicationEvent event) {
|
||||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(event);
|
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(event);
|
||||||
}
|
}
|
||||||
@@ -309,4 +297,16 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
|||||||
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
|
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
|
||||||
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
|
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkTypeCompatability(final SoftwareModule softwareModule) {
|
||||||
|
// we cannot allow that modules are added without a type defined
|
||||||
|
if (type == null) {
|
||||||
|
throw new DistributionSetTypeUndefinedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if it is allowed to such a module to this DS type
|
||||||
|
if (!type.containsModuleType(softwareModule.getType())) {
|
||||||
|
throw new UnsupportedSoftwareModuleForThisDistributionSetException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -24,12 +24,12 @@ import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta data for {@link DistributionSet}.
|
* Meta data for {@link DistributionSet}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@IdClass(DsMetadataCompositeKey.class)
|
@IdClass(DsMetadataCompositeKey.class)
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_ds_metadata")
|
@Table(name = "sp_ds_metadata")
|
||||||
public class JpaDistributionSetMetadata extends AbstractJpaMetaData implements DistributionSetMetadata {
|
public class JpaDistributionSetMetadata extends AbstractJpaMetaData implements DistributionSetMetadata {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@@ -54,15 +54,15 @@ public class JpaDistributionSetMetadata extends AbstractJpaMetaData implements D
|
|||||||
return new DsMetadataCompositeKey(distributionSet.getId(), getKey());
|
return new DsMetadataCompositeKey(distributionSet.getId(), getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDistributionSet(final DistributionSet distributionSet) {
|
|
||||||
this.distributionSet = (JpaDistributionSet) distributionSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DistributionSet getDistributionSet() {
|
public DistributionSet getDistributionSet() {
|
||||||
return distributionSet;
|
return distributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDistributionSet(final DistributionSet distributionSet) {
|
||||||
|
this.distributionSet = (JpaDistributionSet) distributionSet;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.model;
|
package org.eclipse.hawkbit.repository.jpa.model;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
@@ -31,14 +30,14 @@ import org.eclipse.persistence.descriptors.DescriptorEvent;
|
|||||||
/**
|
/**
|
||||||
* A {@link DistributionSetTag} is used to describe DistributionSet attributes
|
* A {@link DistributionSetTag} is used to describe DistributionSet attributes
|
||||||
* and use them also for filtering the DistributionSet list.
|
* and use them also for filtering the DistributionSet list.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_distributionset_tag", indexes = {
|
@Table(name = "sp_distributionset_tag", indexes = {
|
||||||
@Index(name = "sp_idx_distribution_set_tag_prim", columnList = "tenant,id"),
|
@Index(name = "sp_idx_distribution_set_tag_prim", columnList = "tenant,id"),
|
||||||
@Index(name = "sp_idx_distribution_set_tag_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = {
|
@Index(name = "sp_idx_distribution_set_tag_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = {
|
||||||
"name", "tenant" }, name = "uk_ds_tag"))
|
"name", "tenant" }, name = "uk_ds_tag"))
|
||||||
public class JpaDistributionSetTag extends JpaTag implements DistributionSetTag, EventAwareEntity {
|
public class JpaDistributionSetTag extends JpaTag implements DistributionSetTag, EventAwareEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@CascadeOnDelete
|
@CascadeOnDelete
|
||||||
@@ -48,12 +47,9 @@ public class JpaDistributionSetTag extends JpaTag implements DistributionSetTag,
|
|||||||
/**
|
/**
|
||||||
* Public constructor.
|
* Public constructor.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name of the {@link DistributionSetTag}
|
||||||
* of the {@link DistributionSetTag}
|
* @param description of the {@link DistributionSetTag}
|
||||||
* @param description
|
* @param colour of tag in UI
|
||||||
* of the {@link DistributionSetTag}
|
|
||||||
* @param colour
|
|
||||||
* of tag in UI
|
|
||||||
*/
|
*/
|
||||||
public JpaDistributionSetTag(final String name, final String description, final String colour) {
|
public JpaDistributionSetTag(final String name, final String description, final String colour) {
|
||||||
super(name, description, colour);
|
super(name, description, colour);
|
||||||
|
|||||||
@@ -9,6 +9,24 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.model;
|
package org.eclipse.hawkbit.repository.jpa.model;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Index;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.UniqueConstraint;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeUpdatedEvent;
|
||||||
@@ -22,34 +40,16 @@ import org.eclipse.persistence.annotations.CascadeOnDelete;
|
|||||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.FetchType;
|
|
||||||
import jakarta.persistence.Index;
|
|
||||||
import jakarta.persistence.ManyToMany;
|
|
||||||
import jakarta.persistence.OneToMany;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
import jakarta.persistence.UniqueConstraint;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A distribution set type defines which software module types can or have to be
|
* A distribution set type defines which software module types can or have to be
|
||||||
* {@link DistributionSet}.
|
* {@link DistributionSet}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_distribution_set_type", indexes = {
|
@Table(name = "sp_distribution_set_type", indexes = {
|
||||||
@Index(name = "sp_idx_distribution_set_type_01", columnList = "tenant,deleted"),
|
@Index(name = "sp_idx_distribution_set_type_01", columnList = "tenant,deleted"),
|
||||||
@Index(name = "sp_idx_distribution_set_type_prim", columnList = "tenant,id") }, uniqueConstraints = {
|
@Index(name = "sp_idx_distribution_set_type_prim", columnList = "tenant,id") }, uniqueConstraints = {
|
||||||
@UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_dst_name"),
|
@UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_dst_name"),
|
||||||
@UniqueConstraint(columnNames = { "type_key", "tenant" }, name = "uk_dst_key") })
|
@UniqueConstraint(columnNames = { "type_key", "tenant" }, name = "uk_dst_key") })
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
@@ -77,12 +77,9 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
|||||||
/**
|
/**
|
||||||
* Standard constructor.
|
* Standard constructor.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key of the type (unique)
|
||||||
* of the type (unique)
|
* @param name of the type (unique)
|
||||||
* @param name
|
* @param description of the type
|
||||||
* of the type (unique)
|
|
||||||
* @param description
|
|
||||||
* of the type
|
|
||||||
*/
|
*/
|
||||||
public JpaDistributionSetType(final String key, final String name, final String description) {
|
public JpaDistributionSetType(final String key, final String name, final String description) {
|
||||||
this(key, name, description, null);
|
this(key, name, description, null);
|
||||||
@@ -91,14 +88,10 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key of the type
|
||||||
* of the type
|
* @param name of the type
|
||||||
* @param name
|
* @param description of the type
|
||||||
* of the type
|
* @param colour of the type. It will be null by default
|
||||||
* @param description
|
|
||||||
* of the type
|
|
||||||
* @param colour
|
|
||||||
* of the type. It will be null by default
|
|
||||||
*/
|
*/
|
||||||
public JpaDistributionSetType(final String key, final String name, final String description, final String colour) {
|
public JpaDistributionSetType(final String key, final String name, final String description, final String colour) {
|
||||||
super(name, description, key, colour);
|
super(name, description, key, colour);
|
||||||
@@ -144,15 +137,14 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
|||||||
return new HashSet<>(((JpaDistributionSetType) dsType).elements).equals(elements);
|
return new HashSet<>(((JpaDistributionSetType) dsType).elements).equals(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOneModuleListEmpty(final DistributionSetType dsType) {
|
@Override
|
||||||
return (!CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements)
|
public boolean checkComplete(final DistributionSet distributionSet) {
|
||||||
&& CollectionUtils.isEmpty(elements))
|
final List<SoftwareModuleType> smTypes = distributionSet.getModules().stream().map(SoftwareModule::getType)
|
||||||
|| (CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements)
|
.distinct().collect(Collectors.toList());
|
||||||
&& !CollectionUtils.isEmpty(elements));
|
if (smTypes.isEmpty()) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
private boolean areBothModuleListsEmpty(final DistributionSetType dsType) {
|
return smTypes.containsAll(getMandatoryModuleTypes());
|
||||||
return CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements) && CollectionUtils.isEmpty(elements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JpaDistributionSetType addOptionalModuleType(final SoftwareModuleType smType) {
|
public JpaDistributionSetType addOptionalModuleType(final SoftwareModuleType smType) {
|
||||||
@@ -163,26 +155,6 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
|||||||
return setModuleType(smType, true);
|
return setModuleType(smType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JpaDistributionSetType setModuleType(final SoftwareModuleType smType, final boolean mandatory) {
|
|
||||||
if (elements == null) {
|
|
||||||
elements = new HashSet<>();
|
|
||||||
elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if this was in the list before before
|
|
||||||
final Optional<DistributionSetTypeElement> existing = elements.stream()
|
|
||||||
.filter(element -> element.getSmType().getKey().equals(smType.getKey())).findAny();
|
|
||||||
|
|
||||||
if (existing.isPresent()) {
|
|
||||||
existing.get().setMandatory(mandatory);
|
|
||||||
} else {
|
|
||||||
elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JpaDistributionSetType removeModuleType(final Long smTypeId) {
|
public JpaDistributionSetType removeModuleType(final Long smTypeId) {
|
||||||
if (elements == null) {
|
if (elements == null) {
|
||||||
return this;
|
return this;
|
||||||
@@ -195,16 +167,6 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkComplete(final DistributionSet distributionSet) {
|
|
||||||
final List<SoftwareModuleType> smTypes = distributionSet.getModules().stream().map(SoftwareModule::getType)
|
|
||||||
.distinct().collect(Collectors.toList());
|
|
||||||
if (smTypes.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return smTypes.containsAll(getMandatoryModuleTypes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<DistributionSetTypeElement> getElements() {
|
public Set<DistributionSetTypeElement> getElements() {
|
||||||
if (elements == null) {
|
if (elements == null) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
@@ -235,4 +197,35 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
|||||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new DistributionSetTypeDeletedEvent(
|
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new DistributionSetTypeDeletedEvent(
|
||||||
getTenant(), getId(), getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
getTenant(), getId(), getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOneModuleListEmpty(final DistributionSetType dsType) {
|
||||||
|
return (!CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements)
|
||||||
|
&& CollectionUtils.isEmpty(elements))
|
||||||
|
|| (CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements)
|
||||||
|
&& !CollectionUtils.isEmpty(elements));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areBothModuleListsEmpty(final DistributionSetType dsType) {
|
||||||
|
return CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements) && CollectionUtils.isEmpty(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JpaDistributionSetType setModuleType(final SoftwareModuleType smType, final boolean mandatory) {
|
||||||
|
if (elements == null) {
|
||||||
|
elements = new HashSet<>();
|
||||||
|
elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if this was in the list before before
|
||||||
|
final Optional<DistributionSetTypeElement> existing = elements.stream()
|
||||||
|
.filter(element -> element.getSmType().getKey().equals(smType.getKey())).findAny();
|
||||||
|
|
||||||
|
if (existing.isPresent()) {
|
||||||
|
existing.get().setMandatory(mandatory);
|
||||||
|
} else {
|
||||||
|
elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ import org.eclipse.persistence.sessions.changesets.ObjectChangeSet;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA implementation of a {@link Rollout}.
|
* JPA implementation of a {@link Rollout}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_rollout", uniqueConstraints = @UniqueConstraint(columnNames = { "name",
|
@Table(name = "sp_rollout", uniqueConstraints = @UniqueConstraint(columnNames = { "name",
|
||||||
@@ -149,6 +148,62 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
|||||||
@Transient
|
@Transient
|
||||||
private transient TotalTargetCountStatus totalTargetCountStatus;
|
private transient TotalTargetCountStatus totalTargetCountStatus;
|
||||||
|
|
||||||
|
public List<RolloutGroup> getRolloutGroups() {
|
||||||
|
if (rolloutGroups == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(rolloutGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastCheck() {
|
||||||
|
return lastCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastCheck(final long lastCheck) {
|
||||||
|
this.lastCheck = lastCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dynamic is null only for old rollouts - could be used for distinguishing
|
||||||
|
// old once from the other
|
||||||
|
public boolean isNewStyleTargetPercent() {
|
||||||
|
return dynamic != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Rollout [ targetFilterQuery=" + targetFilterQuery + ", distributionSet=" + distributionSet + ", status="
|
||||||
|
+ status + ", lastCheck=" + lastCheck + ", getName()=" + getName() + ", getId()=" + getId() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||||
|
EventPublisherHolder.getInstance().getEventPublisher()
|
||||||
|
.publishEvent(new RolloutCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
||||||
|
EventPublisherHolder.getInstance().getEventPublisher()
|
||||||
|
.publishEvent(new RolloutUpdatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
|
|
||||||
|
if (isSoftDeleted(descriptorEvent)) {
|
||||||
|
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new RolloutDeletedEvent(getTenant(),
|
||||||
|
getId(), getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fireDeleteEvent(final DescriptorEvent descriptorEvent) {
|
||||||
|
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new RolloutDeletedEvent(getTenant(),
|
||||||
|
getId(), getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDeleted() {
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DistributionSet getDistributionSet() {
|
public DistributionSet getDistributionSet() {
|
||||||
return distributionSet;
|
return distributionSet;
|
||||||
@@ -158,14 +213,6 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
|||||||
this.distributionSet = (JpaDistributionSet) distributionSet;
|
this.distributionSet = (JpaDistributionSet) distributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RolloutGroup> getRolloutGroups() {
|
|
||||||
if (rolloutGroups == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(rolloutGroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTargetFilterQuery() {
|
public String getTargetFilterQuery() {
|
||||||
return targetFilterQuery;
|
return targetFilterQuery;
|
||||||
@@ -184,23 +231,6 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastCheck() {
|
|
||||||
return lastCheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastCheck(final long lastCheck) {
|
|
||||||
this.lastCheck = lastCheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getStartAt() {
|
|
||||||
return startAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStartAt(final Long startAt) {
|
|
||||||
this.startAt = startAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionType getActionType() {
|
public ActionType getActionType() {
|
||||||
return actionType;
|
return actionType;
|
||||||
@@ -215,40 +245,13 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
|||||||
return forcedTime;
|
return forcedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForcedTime(final long forcedTime) {
|
|
||||||
this.forcedTime = forcedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Integer> getWeight() {
|
public Long getStartAt() {
|
||||||
return Optional.ofNullable(weight);
|
return startAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWeight(final Integer weight) {
|
public void setStartAt(final Long startAt) {
|
||||||
this.weight = weight;
|
this.startAt = startAt;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDynamic() {
|
|
||||||
return Boolean.TRUE.equals(dynamic);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDynamic(final Boolean dynamic) {
|
|
||||||
this.dynamic = dynamic;
|
|
||||||
}
|
|
||||||
|
|
||||||
// dynamic is null only for old rollouts - could be used for distinguishing
|
|
||||||
// old once from the other
|
|
||||||
public boolean isNewStyleTargetPercent() {
|
|
||||||
return dynamic != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<String> getAccessControlContext() {
|
|
||||||
return Optional.ofNullable(accessControlContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAccessControlContext(final String accessControlContext) {
|
|
||||||
this.accessControlContext = accessControlContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -281,54 +284,6 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
|||||||
this.totalTargetCountStatus = totalTargetCountStatus;
|
this.totalTargetCountStatus = totalTargetCountStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Rollout [ targetFilterQuery=" + targetFilterQuery + ", distributionSet=" + distributionSet + ", status="
|
|
||||||
+ status + ", lastCheck=" + lastCheck + ", getName()=" + getName() + ", getId()=" + getId() + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
|
||||||
EventPublisherHolder.getInstance().getEventPublisher()
|
|
||||||
.publishEvent(new RolloutCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
|
||||||
EventPublisherHolder.getInstance().getEventPublisher()
|
|
||||||
.publishEvent(new RolloutUpdatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
|
||||||
|
|
||||||
if (isSoftDeleted(descriptorEvent)) {
|
|
||||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new RolloutDeletedEvent(getTenant(),
|
|
||||||
getId(), getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isSoftDeleted(final DescriptorEvent event) {
|
|
||||||
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
|
|
||||||
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
|
|
||||||
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
|
|
||||||
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fireDeleteEvent(final DescriptorEvent descriptorEvent) {
|
|
||||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new RolloutDeletedEvent(getTenant(),
|
|
||||||
getId(), getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDeleted() {
|
|
||||||
return deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeleted(final boolean deleted) {
|
|
||||||
this.deleted = deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getApprovalDecidedBy() {
|
public String getApprovalDecidedBy() {
|
||||||
return approvalDecidedBy;
|
return approvalDecidedBy;
|
||||||
@@ -343,7 +298,51 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
|||||||
return approvalRemark;
|
return approvalRemark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Integer> getWeight() {
|
||||||
|
return Optional.ofNullable(weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeight(final Integer weight) {
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDynamic() {
|
||||||
|
return Boolean.TRUE.equals(dynamic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDynamic(final Boolean dynamic) {
|
||||||
|
this.dynamic = dynamic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getAccessControlContext() {
|
||||||
|
return Optional.ofNullable(accessControlContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessControlContext(final String accessControlContext) {
|
||||||
|
this.accessControlContext = accessControlContext;
|
||||||
|
}
|
||||||
|
|
||||||
public void setApprovalRemark(final String approvalRemark) {
|
public void setApprovalRemark(final String approvalRemark) {
|
||||||
this.approvalRemark = approvalRemark;
|
this.approvalRemark = approvalRemark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setForcedTime(final long forcedTime) {
|
||||||
|
this.forcedTime = forcedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeleted(final boolean deleted) {
|
||||||
|
this.deleted = deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSoftDeleted(final DescriptorEvent event) {
|
||||||
|
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
|
||||||
|
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
|
||||||
|
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
|
||||||
|
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import org.eclipse.persistence.descriptors.DescriptorEvent;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA entity definition of persisting a group of an rollout.
|
* JPA entity definition of persisting a group of an rollout.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_rolloutgroup", uniqueConstraints = @UniqueConstraint(columnNames = { "name", "rollout",
|
@Table(name = "sp_rolloutgroup", uniqueConstraints = @UniqueConstraint(columnNames = { "name", "rollout",
|
||||||
@@ -121,7 +120,7 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
|
|||||||
|
|
||||||
@Column(name = "target_percentage")
|
@Column(name = "target_percentage")
|
||||||
private float targetPercentage = 100;
|
private float targetPercentage = 100;
|
||||||
|
|
||||||
@Column(name = "confirmation_required")
|
@Column(name = "confirmation_required")
|
||||||
private boolean confirmationRequired;
|
private boolean confirmationRequired;
|
||||||
|
|
||||||
@@ -146,14 +145,6 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RolloutTargetGroup> getRolloutTargetGroup() {
|
|
||||||
if (rolloutTargetGroup == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(rolloutTargetGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RolloutGroup getParent() {
|
public RolloutGroup getParent() {
|
||||||
return parent;
|
return parent;
|
||||||
@@ -168,10 +159,6 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
|
|||||||
this.dynamic = dynamic;
|
this.dynamic = dynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParent(final RolloutGroup parent) {
|
|
||||||
this.parent = (JpaRolloutGroup) parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RolloutGroupSuccessCondition getSuccessCondition() {
|
public RolloutGroupSuccessCondition getSuccessCondition() {
|
||||||
return successCondition;
|
return successCondition;
|
||||||
@@ -245,12 +232,15 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
|
|||||||
this.totalTargets = totalTargets;
|
this.totalTargets = totalTargets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSuccessAction(final RolloutGroupSuccessAction successAction) {
|
/**
|
||||||
this.successAction = successAction;
|
* @return the totalTargetCountStatus
|
||||||
}
|
*/
|
||||||
|
@Override
|
||||||
public void setSuccessActionExp(final String successActionExp) {
|
public TotalTargetCountStatus getTotalTargetCountStatus() {
|
||||||
this.successActionExp = successActionExp;
|
if (totalTargetCountStatus == null) {
|
||||||
|
totalTargetCountStatus = new TotalTargetCountStatus(Long.valueOf(totalTargets), rollout.getActionType());
|
||||||
|
}
|
||||||
|
return totalTargetCountStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -267,38 +257,46 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
|
|||||||
return targetPercentage;
|
return targetPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfirmationRequired(final boolean confirmationRequired) {
|
|
||||||
this.confirmationRequired = confirmationRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConfirmationRequired() {
|
public boolean isConfirmationRequired() {
|
||||||
return confirmationRequired;
|
return confirmationRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setConfirmationRequired(final boolean confirmationRequired) {
|
||||||
|
this.confirmationRequired = confirmationRequired;
|
||||||
|
}
|
||||||
|
|
||||||
public void setTargetPercentage(final float targetPercentage) {
|
public void setTargetPercentage(final float targetPercentage) {
|
||||||
this.targetPercentage = targetPercentage;
|
this.targetPercentage = targetPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the totalTargetCountStatus
|
* @param totalTargetCountStatus the totalTargetCountStatus to set
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public TotalTargetCountStatus getTotalTargetCountStatus() {
|
|
||||||
if (totalTargetCountStatus == null) {
|
|
||||||
totalTargetCountStatus = new TotalTargetCountStatus(Long.valueOf(totalTargets), rollout.getActionType());
|
|
||||||
}
|
|
||||||
return totalTargetCountStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param totalTargetCountStatus
|
|
||||||
* the totalTargetCountStatus to set
|
|
||||||
*/
|
*/
|
||||||
public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) {
|
public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) {
|
||||||
this.totalTargetCountStatus = totalTargetCountStatus;
|
this.totalTargetCountStatus = totalTargetCountStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSuccessActionExp(final String successActionExp) {
|
||||||
|
this.successActionExp = successActionExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccessAction(final RolloutGroupSuccessAction successAction) {
|
||||||
|
this.successAction = successAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(final RolloutGroup parent) {
|
||||||
|
this.parent = (JpaRolloutGroup) parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RolloutTargetGroup> getRolloutTargetGroup() {
|
||||||
|
if (rolloutTargetGroup == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(rolloutTargetGroup);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RolloutGroup [rollout=" + (rollout != null ? rollout.getId() : "") + ", status=" + status
|
return "RolloutGroup [rollout=" + (rollout != null ? rollout.getId() : "") + ", status=" + status
|
||||||
|
|||||||
@@ -62,9 +62,9 @@ import org.eclipse.persistence.sessions.changesets.ObjectChangeSet;
|
|||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_base_software_module", uniqueConstraints = @UniqueConstraint(columnNames = { "module_type", "name",
|
@Table(name = "sp_base_software_module", uniqueConstraints = @UniqueConstraint(columnNames = { "module_type", "name",
|
||||||
"version", "tenant" }, name = "uk_base_sw_mod"), indexes = {
|
"version", "tenant" }, name = "uk_base_sw_mod"), indexes = {
|
||||||
@Index(name = "sp_idx_base_sw_module_01", columnList = "tenant,deleted,name,version"),
|
@Index(name = "sp_idx_base_sw_module_01", columnList = "tenant,deleted,name,version"),
|
||||||
@Index(name = "sp_idx_base_sw_module_02", columnList = "tenant,deleted,module_type"),
|
@Index(name = "sp_idx_base_sw_module_02", columnList = "tenant,deleted,module_type"),
|
||||||
@Index(name = "sp_idx_base_sw_module_prim", columnList = "tenant,id") })
|
@Index(name = "sp_idx_base_sw_module_prim", columnList = "tenant,id") })
|
||||||
@NamedEntityGraph(name = "SoftwareModule.artifacts", attributeNodes = { @NamedAttributeNode("artifacts") })
|
@NamedEntityGraph(name = "SoftwareModule.artifacts", attributeNodes = { @NamedAttributeNode("artifacts") })
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
// sub entities
|
// sub entities
|
||||||
@@ -83,7 +83,8 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
|
|||||||
private JpaSoftwareModuleType type;
|
private JpaSoftwareModuleType type;
|
||||||
|
|
||||||
@CascadeOnDelete
|
@CascadeOnDelete
|
||||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "softwareModule", cascade = { CascadeType.PERSIST }, targetEntity = JpaArtifact.class, orphanRemoval = true)
|
@OneToMany(fetch = FetchType.LAZY, mappedBy = "softwareModule", cascade = {
|
||||||
|
CascadeType.PERSIST }, targetEntity = JpaArtifact.class, orphanRemoval = true)
|
||||||
private List<JpaArtifact> artifacts;
|
private List<JpaArtifact> artifacts;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@@ -191,7 +192,8 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
|
|||||||
}
|
}
|
||||||
sb.delete(sb.length() - 2, sb.length());
|
sb.delete(sb.length() - 2, sb.length());
|
||||||
throw new LockedException(JpaSoftwareModule.class, getId(), "DELETE", sb.toString());
|
throw new LockedException(JpaSoftwareModule.class, getId(), "DELETE", sb.toString());
|
||||||
};
|
}
|
||||||
|
;
|
||||||
}
|
}
|
||||||
this.deleted = deleted;
|
this.deleted = deleted;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata for {@link SoftwareModule}.
|
* Metadata for {@link SoftwareModule}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@IdClass(SwMetadataCompositeKey.class)
|
@IdClass(SwMetadataCompositeKey.class)
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_sw_metadata")
|
@Table(name = "sp_sw_metadata")
|
||||||
public class JpaSoftwareModuleMetadata extends AbstractJpaMetaData implements SoftwareModuleMetadata {
|
public class JpaSoftwareModuleMetadata extends AbstractJpaMetaData implements SoftwareModuleMetadata {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.model;
|
package org.eclipse.hawkbit.repository.jpa.model;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Index;
|
import jakarta.persistence.Index;
|
||||||
@@ -23,18 +25,15 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
|||||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of a software modules.
|
* Type of a software modules.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_software_module_type", indexes = {
|
@Table(name = "sp_software_module_type", indexes = {
|
||||||
@Index(name = "sp_idx_software_module_type_01", columnList = "tenant,deleted"),
|
@Index(name = "sp_idx_software_module_type_01", columnList = "tenant,deleted"),
|
||||||
@Index(name = "sp_idx_software_module_type_prim", columnList = "tenant,id") }, uniqueConstraints = {
|
@Index(name = "sp_idx_software_module_type_prim", columnList = "tenant,id") }, uniqueConstraints = {
|
||||||
@UniqueConstraint(columnNames = { "type_key", "tenant" }, name = "uk_smt_type_key"),
|
@UniqueConstraint(columnNames = { "type_key", "tenant" }, name = "uk_smt_type_key"),
|
||||||
@UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_smt_name") })
|
@UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_smt_name") })
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
@@ -53,14 +52,10 @@ public class JpaSoftwareModuleType extends AbstractJpaTypeEntity implements Soft
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key of the type
|
||||||
* of the type
|
* @param name of the type
|
||||||
* @param name
|
* @param description of the type
|
||||||
* of the type
|
* @param maxAssignments assignments to a DS
|
||||||
* @param description
|
|
||||||
* of the type
|
|
||||||
* @param maxAssignments
|
|
||||||
* assignments to a DS
|
|
||||||
*/
|
*/
|
||||||
public JpaSoftwareModuleType(final String key, final String name, final String description,
|
public JpaSoftwareModuleType(final String key, final String name, final String description,
|
||||||
final int maxAssignments) {
|
final int maxAssignments) {
|
||||||
@@ -70,16 +65,11 @@ public class JpaSoftwareModuleType extends AbstractJpaTypeEntity implements Soft
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key of the type
|
||||||
* of the type
|
* @param name of the type
|
||||||
* @param name
|
* @param description of the type
|
||||||
* of the type
|
* @param maxAssignments assignments to a DS
|
||||||
* @param description
|
* @param colour of the type. It will be null by default
|
||||||
* of the type
|
|
||||||
* @param maxAssignments
|
|
||||||
* assignments to a DS
|
|
||||||
* @param colour
|
|
||||||
* of the type. It will be null by default
|
|
||||||
*/
|
*/
|
||||||
public JpaSoftwareModuleType(final String key, final String name, final String description,
|
public JpaSoftwareModuleType(final String key, final String name, final String description,
|
||||||
final int maxAssignments, final String colour) {
|
final int maxAssignments, final String colour) {
|
||||||
@@ -94,15 +84,15 @@ public class JpaSoftwareModuleType extends AbstractJpaTypeEntity implements Soft
|
|||||||
// Default Constructor for JPA.
|
// Default Constructor for JPA.
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMaxAssignments(final int maxAssignments) {
|
|
||||||
this.maxAssignments = maxAssignments;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxAssignments() {
|
public int getMaxAssignments() {
|
||||||
return maxAssignments;
|
return maxAssignments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxAssignments(final int maxAssignments) {
|
||||||
|
this.maxAssignments = maxAssignments;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDeleted() {
|
public boolean isDeleted() {
|
||||||
return deleted;
|
return deleted;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
package org.eclipse.hawkbit.repository.jpa.model;
|
package org.eclipse.hawkbit.repository.jpa.model;
|
||||||
|
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.model.Statistic;
|
import org.eclipse.hawkbit.repository.model.Statistic;
|
||||||
|
|
||||||
public interface JpaStatistic extends Statistic {
|
public interface JpaStatistic extends Statistic {
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ import org.eclipse.hawkbit.repository.model.Tag;
|
|||||||
/**
|
/**
|
||||||
* A Tag can be used as describing and organizational meta information for any
|
* A Tag can be used as describing and organizational meta information for any
|
||||||
* kind of entity.
|
* kind of entity.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
public class JpaTag extends AbstractJpaNamedEntity implements Tag {
|
public class JpaTag extends AbstractJpaNamedEntity implements Tag {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Column(name = "colour", nullable = true, length = Tag.COLOUR_MAX_SIZE)
|
@Column(name = "colour", nullable = true, length = Tag.COLOUR_MAX_SIZE)
|
||||||
@@ -38,12 +38,9 @@ public class JpaTag extends AbstractJpaNamedEntity implements Tag {
|
|||||||
/**
|
/**
|
||||||
* Public constructor.
|
* Public constructor.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name of the {@link Tag}
|
||||||
* of the {@link Tag}
|
* @param description of the {@link Tag}
|
||||||
* @param description
|
* @param colour of tag in UI
|
||||||
* of the {@link Tag}
|
|
||||||
* @param colour
|
|
||||||
* of tag in UI
|
|
||||||
*/
|
*/
|
||||||
public JpaTag(final String name, final String description, final String colour) {
|
public JpaTag(final String name, final String description, final String colour) {
|
||||||
super(name, description);
|
super(name, description);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent;
|
|||||||
@Index(name = "sp_idx_target_04", columnList = "tenant,created_at"),
|
@Index(name = "sp_idx_target_04", columnList = "tenant,created_at"),
|
||||||
@Index(name = "sp_idx_target_05", columnList = "tenant,last_modified_at"),
|
@Index(name = "sp_idx_target_05", columnList = "tenant,last_modified_at"),
|
||||||
@Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = {
|
@Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = {
|
||||||
"controller_id", "tenant" }, name = "uk_tenant_controller_id"))
|
"controller_id", "tenant" }, name = "uk_tenant_controller_id"))
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
// sub entities
|
// sub entities
|
||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
@@ -218,91 +218,25 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return assignedDistributionSet;
|
return assignedDistributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param assignedDistributionSet Distribution set
|
||||||
|
*/
|
||||||
|
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
|
||||||
|
this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getControllerId() {
|
public String getControllerId() {
|
||||||
return controllerId;
|
return controllerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return tags
|
* @param controllerId Controller ID
|
||||||
*/
|
|
||||||
public Set<TargetTag> getTags() {
|
|
||||||
if (tags == null) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableSet(tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return rollouts target group
|
|
||||||
*/
|
|
||||||
public List<RolloutTargetGroup> getRolloutTargetGroup() {
|
|
||||||
if (rolloutTargetGroup == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(rolloutTargetGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tag
|
|
||||||
* to be added
|
|
||||||
*/
|
|
||||||
public void addTag(final TargetTag tag) {
|
|
||||||
if (tags == null) {
|
|
||||||
tags = new HashSet<>();
|
|
||||||
}
|
|
||||||
tags.add(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tag
|
|
||||||
* the tag to be removed from the target
|
|
||||||
*/
|
|
||||||
public void removeTag(final TargetTag tag) {
|
|
||||||
if (tags != null) {
|
|
||||||
tags.remove(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param assignedDistributionSet
|
|
||||||
* Distribution set
|
|
||||||
*/
|
|
||||||
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
|
|
||||||
this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param controllerId
|
|
||||||
* Controller ID
|
|
||||||
*/
|
*/
|
||||||
public void setControllerId(final String controllerId) {
|
public void setControllerId(final String controllerId) {
|
||||||
this.controllerId = controllerId;
|
this.controllerId = controllerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return list of action
|
|
||||||
*/
|
|
||||||
public List<Action> getActions() {
|
|
||||||
if (actions == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(actions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param action
|
|
||||||
* Action
|
|
||||||
*/
|
|
||||||
public void addAction(final Action action) {
|
|
||||||
if (actions == null) {
|
|
||||||
actions = new ArrayList<>();
|
|
||||||
}
|
|
||||||
actions.add((JpaAction) action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the securityToken if the current security context contains the
|
* @return the securityToken if the current security context contains the
|
||||||
* necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN}
|
* necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN}
|
||||||
@@ -321,8 +255,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param securityToken
|
* @param securityToken token value
|
||||||
* token value
|
|
||||||
*/
|
*/
|
||||||
public void setSecurityToken(final String securityToken) {
|
public void setSecurityToken(final String securityToken) {
|
||||||
this.securityToken = securityToken;
|
this.securityToken = securityToken;
|
||||||
@@ -344,6 +277,26 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLastTargetQuery() {
|
||||||
|
return lastTargetQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getInstallationDate() {
|
||||||
|
return installationDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TargetUpdateStatus getUpdateStatus() {
|
||||||
|
return updateStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TargetType getTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the poll time which holds the last poll time of the target, the
|
* @return the poll time which holds the last poll time of the target, the
|
||||||
* next poll time and the overdue time. In case the
|
* next poll time and the overdue time. In case the
|
||||||
@@ -366,37 +319,117 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setAutoConfirmationStatus(final JpaAutoConfirmationStatus autoConfirmationStatus) {
|
public void setAutoConfirmationStatus(final JpaAutoConfirmationStatus autoConfirmationStatus) {
|
||||||
this.autoConfirmationStatus = autoConfirmationStatus;
|
this.autoConfirmationStatus = autoConfirmationStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getLastTargetQuery() {
|
public boolean isRequestControllerAttributes() {
|
||||||
return lastTargetQuery;
|
return requestControllerAttributes;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getInstallationDate() {
|
|
||||||
return installationDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetUpdateStatus getUpdateStatus() {
|
|
||||||
return updateStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetType getTargetType() {
|
|
||||||
return targetType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param type
|
* @param requestControllerAttributes Attributes
|
||||||
* Target type
|
*/
|
||||||
|
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
|
||||||
|
this.requestControllerAttributes = requestControllerAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type Target type
|
||||||
*/
|
*/
|
||||||
public void setTargetType(final TargetType type) {
|
public void setTargetType(final TargetType type) {
|
||||||
this.targetType = type;
|
this.targetType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param updateStatus Status
|
||||||
|
*/
|
||||||
|
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
|
||||||
|
this.updateStatus = updateStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param installationDate installation date
|
||||||
|
*/
|
||||||
|
public void setInstallationDate(final Long installationDate) {
|
||||||
|
this.installationDate = installationDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param lastTargetQuery last query ID
|
||||||
|
*/
|
||||||
|
public void setLastTargetQuery(final Long lastTargetQuery) {
|
||||||
|
this.lastTargetQuery = lastTargetQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param address Address
|
||||||
|
*/
|
||||||
|
public void setAddress(final String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return tags
|
||||||
|
*/
|
||||||
|
public Set<TargetTag> getTags() {
|
||||||
|
if (tags == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableSet(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return rollouts target group
|
||||||
|
*/
|
||||||
|
public List<RolloutTargetGroup> getRolloutTargetGroup() {
|
||||||
|
if (rolloutTargetGroup == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(rolloutTargetGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag to be added
|
||||||
|
*/
|
||||||
|
public void addTag(final TargetTag tag) {
|
||||||
|
if (tags == null) {
|
||||||
|
tags = new HashSet<>();
|
||||||
|
}
|
||||||
|
tags.add(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag the tag to be removed from the target
|
||||||
|
*/
|
||||||
|
public void removeTag(final TargetTag tag) {
|
||||||
|
if (tags != null) {
|
||||||
|
tags.remove(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list of action
|
||||||
|
*/
|
||||||
|
public List<Action> getActions() {
|
||||||
|
if (actions == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param action Action
|
||||||
|
*/
|
||||||
|
public void addAction(final Action action) {
|
||||||
|
if (actions == null) {
|
||||||
|
actions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
actions.add((JpaAction) action);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Distribution set
|
* @return Distribution set
|
||||||
*/
|
*/
|
||||||
@@ -404,6 +437,13 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return installedDistributionSet;
|
return installedDistributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param installedDistributionSet Distribution set
|
||||||
|
*/
|
||||||
|
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
|
||||||
|
this.installedDistributionSet = installedDistributionSet;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return controller attributes
|
* @return controller attributes
|
||||||
*/
|
*/
|
||||||
@@ -411,11 +451,6 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return controllerAttributes;
|
return controllerAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRequestControllerAttributes() {
|
|
||||||
return requestControllerAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return target metadata
|
* @return target metadata
|
||||||
*/
|
*/
|
||||||
@@ -433,65 +468,12 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param address
|
|
||||||
* Address
|
|
||||||
*/
|
|
||||||
public void setAddress(final String address) {
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param lastTargetQuery
|
|
||||||
* last query ID
|
|
||||||
*/
|
|
||||||
public void setLastTargetQuery(final Long lastTargetQuery) {
|
|
||||||
this.lastTargetQuery = lastTargetQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param installationDate
|
|
||||||
* installation date
|
|
||||||
*/
|
|
||||||
public void setInstallationDate(final Long installationDate) {
|
|
||||||
this.installationDate = installationDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param installedDistributionSet
|
|
||||||
* Distribution set
|
|
||||||
*/
|
|
||||||
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
|
|
||||||
this.installedDistributionSet = installedDistributionSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param updateStatus
|
|
||||||
* Status
|
|
||||||
*/
|
|
||||||
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
|
|
||||||
this.updateStatus = updateStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param requestControllerAttributes
|
|
||||||
* Attributes
|
|
||||||
*/
|
|
||||||
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
|
|
||||||
this.requestControllerAttributes = requestControllerAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||||
EventPublisherHolder.getInstance().getEventPublisher()
|
EventPublisherHolder.getInstance().getEventPublisher()
|
||||||
.publishEvent(new TargetCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
.publishEvent(new TargetCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getUpdateIgnoreFields() {
|
|
||||||
return TARGET_UPDATE_EVENT_IGNORE_FIELDS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
||||||
EventPublisherHolder.getInstance().getEventPublisher()
|
EventPublisherHolder.getInstance().getEventPublisher()
|
||||||
@@ -504,4 +486,9 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
.publishEvent(new TargetDeletedEvent(getTenant(), getId(), getControllerId(), address,
|
.publishEvent(new TargetDeletedEvent(getTenant(), getId(), getControllerId(), address,
|
||||||
getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
getClass(), EventPublisherHolder.getInstance().getApplicationId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUpdateIgnoreFields() {
|
||||||
|
return TARGET_UPDATE_EVENT_IGNORE_FIELDS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import org.eclipse.persistence.descriptors.DescriptorEvent;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stored target filter.
|
* Stored target filter.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "sp_target_filter_query", uniqueConstraints = @UniqueConstraint(columnNames = { "name",
|
@Table(name = "sp_target_filter_query", uniqueConstraints = @UniqueConstraint(columnNames = { "name",
|
||||||
@@ -49,6 +48,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent;
|
|||||||
@SuppressWarnings("squid:S2160")
|
@SuppressWarnings("squid:S2160")
|
||||||
public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
||||||
implements TargetFilterQuery, EventAwareEntity {
|
implements TargetFilterQuery, EventAwareEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Column(name = "name", length = NamedEntity.NAME_MAX_SIZE, nullable = false)
|
@Column(name = "name", length = NamedEntity.NAME_MAX_SIZE, nullable = false)
|
||||||
@@ -93,19 +93,13 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a Target filter query with auto assign distribution set
|
* Construct a Target filter query with auto assign distribution set
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name of the {@link TargetFilterQuery}.
|
||||||
* of the {@link TargetFilterQuery}.
|
* @param query of the {@link TargetFilterQuery}.
|
||||||
* @param query
|
* @param autoAssignDistributionSet of the {@link TargetFilterQuery}.
|
||||||
* of the {@link TargetFilterQuery}.
|
* @param autoAssignActionType of the {@link TargetFilterQuery}.
|
||||||
* @param autoAssignDistributionSet
|
* @param autoAssignWeight of the {@link TargetFilterQuery}.
|
||||||
* of the {@link TargetFilterQuery}.
|
* @param confirmationRequired of the {@link TargetFilterQuery}.
|
||||||
* @param autoAssignActionType
|
|
||||||
* of the {@link TargetFilterQuery}.
|
|
||||||
* @param autoAssignWeight
|
|
||||||
* of the {@link TargetFilterQuery}.
|
|
||||||
* @param confirmationRequired
|
|
||||||
* of the {@link TargetFilterQuery}.
|
|
||||||
*/
|
*/
|
||||||
public JpaTargetFilterQuery(final String name, final String query, final DistributionSet autoAssignDistributionSet,
|
public JpaTargetFilterQuery(final String name, final String query, final DistributionSet autoAssignDistributionSet,
|
||||||
final ActionType autoAssignActionType, final Integer autoAssignWeight, final boolean confirmationRequired) {
|
final ActionType autoAssignActionType, final Integer autoAssignWeight, final boolean confirmationRequired) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user