Fine grained repository permissions (#2562)
1. Introduce @PrreAuthorize check based on hasPermission - allowing custom processing (compared with non-modifiable hasAuthority/Role processing) 2. Dedicated permissions could be implemented on management api level. Check is made by plugged in PermissionEvaluator 3. Thus common XXX_REPOSITORY permissions could differ for extending services 4. Change create/update entity builder pattern - not via EntityFactory but via clean static lombok based builders (with fine fluent api). 5. Implement abstract repository management jpa class that handles the boilerplate code from extending classes in single place consistently -> AbsreactJpaRepositoryManagement 6. Register management api-s as **Sevice**-s instead of **Bean**-s in order to make easier maintainable and get away from heavy argument forwading 7. Simplify custom hawkbit repository registration + adding proxy to handle exception mapping at lower level - thus not depending on Aspects for converting exceptions 8. Implemented general purpose 'copy' utility (ObjectCopyUtil) that using getter/setter patterns is able to copy (e.g. Create/Update) objects to other objects (e.g. JPA entity objects)
This commit is contained in:
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.BaseRepositoryTypeProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* A {@link JpaRepositoryFactoryBean} extension that allow injection of custom repository factories by using a
|
||||
* {@link BaseRepositoryTypeProvider} implementation, allows injecting different base repository implementations based on repository type
|
||||
*/
|
||||
@SuppressWarnings("java:S119") // java:S119 - ID is inherited from JpaRepositoryFactoryBean
|
||||
public class CustomBaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID> extends JpaRepositoryFactoryBean<T, S, ID> {
|
||||
|
||||
private BaseRepositoryTypeProvider baseRepoProvider;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
|
||||
*
|
||||
* @param repositoryInterface must not be {@literal null}.
|
||||
*/
|
||||
public CustomBaseRepositoryFactoryBean(final Class<? extends T> repositoryInterface) {
|
||||
super(repositoryInterface);
|
||||
}
|
||||
|
||||
@Autowired // if it is a constructor injection sometimes doesn't work - base repo provider is not available at construct time
|
||||
public void setBaseRepoProvider(final BaseRepositoryTypeProvider baseRepoProvider) {
|
||||
this.baseRepoProvider = baseRepoProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RepositoryFactorySupport createRepositoryFactory(@NonNull final EntityManager entityManager) {
|
||||
final RepositoryFactorySupport rfs = super.createRepositoryFactory(entityManager);
|
||||
rfs.setRepositoryBaseClass(baseRepoProvider.getBaseRepositoryType(getObjectType()));
|
||||
return rfs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.HawkbitBaseRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.repository.query.EscapeCharacter;
|
||||
import org.springframework.data.jpa.repository.query.JpaQueryMethodFactory;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.querydsl.EntityPathResolver;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link TransactionalRepositoryFactoryBeanSupport} extension that uses {@link HawkbitBaseRepository} as base repository and
|
||||
* proxied repositories in order to convert exceptions to management exceptions.
|
||||
*/
|
||||
@SuppressWarnings("java:S119") // java:S119 - ID is inherited from TransactionalRepositoryFactoryBeanSupport
|
||||
public class HawkbitBaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID> extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {
|
||||
|
||||
private EntityPathResolver entityPathResolver;
|
||||
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
|
||||
private JpaQueryMethodFactory queryMethodFactory;
|
||||
|
||||
@Nullable
|
||||
private EntityManager entityManager;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
|
||||
*
|
||||
* @param repositoryInterface must not be {@literal null}.
|
||||
*/
|
||||
public HawkbitBaseRepositoryFactoryBean(final Class<? extends T> repositoryInterface) {
|
||||
super(repositoryInterface);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setEntityPathResolver(final ObjectProvider<EntityPathResolver> resolver) {
|
||||
this.entityPathResolver = resolver.getIfAvailable(() -> SimpleEntityPathResolver.INSTANCE);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setEscapeCharacter(final char escapeCharacter) {
|
||||
this.escapeCharacter = EscapeCharacter.of(escapeCharacter);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setQueryMethodFactory(@Nullable final JpaQueryMethodFactory factory) {
|
||||
if (factory != null) {
|
||||
this.queryMethodFactory = factory;
|
||||
}
|
||||
}
|
||||
|
||||
@PersistenceContext
|
||||
public void setEntityManager(final EntityManager entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Objects.requireNonNull(entityManager, "EntityManager must not be null");
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMappingContext(final MappingContext<?, ?> mappingContext) {
|
||||
super.setMappingContext(mappingContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RepositoryFactorySupport doCreateRepositoryFactory() {
|
||||
Objects.requireNonNull(entityManager, "EntityManager must not be null");
|
||||
final JpaRepositoryFactory jpaRepositoryFactory = new JpaRepositoryFactory(entityManager) {
|
||||
|
||||
@Override
|
||||
protected JpaRepositoryImplementation<?, ?> getTargetRepository(
|
||||
final RepositoryInformation information, final EntityManager entityManager) {
|
||||
final JpaRepositoryImplementation<?, ?> jpaRepositoryImplementation = super.getTargetRepository(information, entityManager);
|
||||
return (JpaRepositoryImplementation<?, ?>) Proxy.newProxyInstance(
|
||||
jpaRepositoryImplementation.getClass().getClassLoader(),
|
||||
interfaces(jpaRepositoryImplementation.getClass(), new HashSet<>()).toArray(new Class<?>[0]),
|
||||
(proxy, method, args) -> {
|
||||
try {
|
||||
return method.invoke(jpaRepositoryImplementation, args);
|
||||
} catch (final InvocationTargetException e) {
|
||||
final Throwable cause = e.getCause() == null ? e : e.getCause();
|
||||
throw cause instanceof Exception exc ? ExceptionMapper.map(exc) : e;
|
||||
} catch (final Exception e) {
|
||||
throw ExceptionMapper.map(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
jpaRepositoryFactory.setEntityPathResolver(entityPathResolver);
|
||||
jpaRepositoryFactory.setEscapeCharacter(escapeCharacter);
|
||||
|
||||
if (queryMethodFactory != null) {
|
||||
jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory);
|
||||
}
|
||||
jpaRepositoryFactory.setRepositoryBaseClass(HawkbitBaseRepository.class);
|
||||
return jpaRepositoryFactory;
|
||||
}
|
||||
|
||||
private static Set<Class<?>> interfaces(final Class<?> type, final Set<Class<?>> interfaces) {
|
||||
Collections.addAll(interfaces, type.getInterfaces());
|
||||
final Class<?> superclass = type.getSuperclass();
|
||||
if (superclass != null && superclass != Object.class) {
|
||||
return interfaces(superclass, interfaces);
|
||||
} else {
|
||||
return interfaces;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,21 +11,17 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TagBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
@@ -37,26 +33,19 @@ public class JpaEntityFactory implements EntityFactory {
|
||||
private final TargetBuilder targetBuilder;
|
||||
private final TargetTypeBuilder targetTypeBuilder;
|
||||
private final TargetFilterQueryBuilder targetFilterQueryBuilder;
|
||||
private final SoftwareModuleBuilder softwareModuleBuilder;
|
||||
private final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder;
|
||||
private final DistributionSetBuilder distributionSetBuilder;
|
||||
private final DistributionSetTypeBuilder distributionSetTypeBuilder;
|
||||
private final RolloutBuilder rolloutBuilder;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaEntityFactory(
|
||||
final TargetBuilder targetBuilder, final TargetTypeBuilder targetTypeBuilder,
|
||||
final TargetFilterQueryBuilder targetFilterQueryBuilder,
|
||||
final SoftwareModuleBuilder softwareModuleBuilder, final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder,
|
||||
final DistributionSetBuilder distributionSetBuilder, final DistributionSetTypeBuilder distributionSetTypeBuilder,
|
||||
final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder,
|
||||
final RolloutBuilder rolloutBuilder) {
|
||||
this.targetBuilder = targetBuilder;
|
||||
this.targetTypeBuilder = targetTypeBuilder;
|
||||
this.targetFilterQueryBuilder = targetFilterQueryBuilder;
|
||||
this.softwareModuleBuilder = softwareModuleBuilder;
|
||||
this.softwareModuleMetadataBuilder = softwareModuleMetadataBuilder;
|
||||
this.distributionSetBuilder = distributionSetBuilder;
|
||||
this.distributionSetTypeBuilder = distributionSetTypeBuilder;
|
||||
this.rolloutBuilder = rolloutBuilder;
|
||||
}
|
||||
@Override
|
||||
@@ -64,46 +53,27 @@ public class JpaEntityFactory implements EntityFactory {
|
||||
return new JpaActionStatusBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetBuilder distributionSet() {
|
||||
return distributionSetBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleMetadataBuilder softwareModuleMetadata() {
|
||||
return softwareModuleMetadataBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder tag() {
|
||||
return new JpaTagBuilder();
|
||||
public TagBuilder<Tag> tag() {
|
||||
return (TagBuilder)new JpaTagBuilder();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RolloutGroupBuilder rolloutGroup() {
|
||||
return new JpaRolloutGroupBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetTypeBuilder distributionSetType() {
|
||||
return distributionSetTypeBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RolloutBuilder rollout() {
|
||||
return rolloutBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleBuilder softwareModule() {
|
||||
return softwareModuleBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleTypeBuilder softwareModuleType() {
|
||||
return new JpaSoftwareModuleTypeBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetBuilder target() {
|
||||
return targetBuilder;
|
||||
|
||||
@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -19,19 +18,10 @@ import jakarta.persistence.EntityManager;
|
||||
import jakarta.validation.Validation;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.artifact.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.cache.TenancyCacheManager;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryption;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionSecretsStore;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.BaseRepositoryTypeProvider;
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.PropertiesQuotaManagement;
|
||||
@@ -44,20 +34,16 @@ import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutHandler;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryption;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionSecretsStore;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
@@ -73,38 +59,18 @@ import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignScheduler;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoActionCleanup;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoCleanupScheduler;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.CleanupTask;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.cluster.LockProperties;
|
||||
import org.eclipse.hawkbit.repository.jpa.cluster.DistributedLockRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.cluster.LockProperties;
|
||||
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitDefaultServiceExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetInvalidationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaRolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaRolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSystemManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
@@ -118,24 +84,16 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
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.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TenantConfigurationRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TenantMetaDataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.RolloutScheduler;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.PauseRolloutGroupAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator;
|
||||
@@ -144,25 +102,19 @@ import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupEvaluati
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -172,16 +124,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.integration.jdbc.lock.DefaultLockRepository;
|
||||
@@ -192,14 +141,19 @@ import org.springframework.integration.support.locks.LockRegistry;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.retry.annotation.EnableRetry;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.security.authorization.AuthorizationDeniedException;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 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 = HawkbitBaseRepositoryFactoryBean.class)
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaAuditing
|
||||
@EnableAspectJAutoProxy
|
||||
@@ -207,8 +161,10 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
||||
@EnableScheduling
|
||||
@EnableRetry
|
||||
@EntityScan("org.eclipse.hawkbit.repository.jpa.model")
|
||||
@ComponentScan("org.eclipse.hawkbit.repository.jpa.management")
|
||||
@PropertySource("classpath:/hawkbit-jpa-defaults.properties")
|
||||
@Import({ JpaConfiguration.class, RepositoryConfiguration.class, LockProperties.class, DataSourceAutoConfiguration.class, SystemManagementCacheKeyGenerator.class })
|
||||
@Import({ JpaConfiguration.class, RepositoryConfiguration.class, LockProperties.class, DataSourceAutoConfiguration.class,
|
||||
SystemManagementCacheKeyGenerator.class })
|
||||
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
|
||||
public class JpaRepositoryConfiguration {
|
||||
|
||||
@@ -224,7 +180,8 @@ public class JpaRepositoryConfiguration {
|
||||
// methods shall not be called - we need the validator in future
|
||||
processor.setValidator(Validation.byDefaultProvider()
|
||||
.configure()
|
||||
.addProperty(org.hibernate.validator.BaseHibernateValidatorConfiguration.ALLOW_PARALLEL_METHODS_DEFINE_PARAMETER_CONSTRAINTS, "true")
|
||||
.addProperty(org.hibernate.validator.BaseHibernateValidatorConfiguration.ALLOW_PARALLEL_METHODS_DEFINE_PARAMETER_CONSTRAINTS,
|
||||
"true")
|
||||
.buildValidatorFactory()
|
||||
.getValidator());
|
||||
return processor;
|
||||
@@ -270,7 +227,8 @@ public class JpaRepositoryConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "hawkbit.lock", havingValue = "distributed", matchIfMissing = true)
|
||||
@ConditionalOnMissingBean
|
||||
LockRepository lockRepository(final DataSource dataSource, final LockProperties lockProperties, final PlatformTransactionManager txManager) {
|
||||
LockRepository lockRepository(final DataSource dataSource, final LockProperties lockProperties,
|
||||
final PlatformTransactionManager txManager) {
|
||||
final DefaultLockRepository repository = new DistributedLockRepository(dataSource, lockProperties, txManager);
|
||||
repository.setPrefix("SP_");
|
||||
return repository;
|
||||
@@ -279,7 +237,7 @@ public class JpaRepositoryConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LockRegistry lockRegistry(final Optional<LockRepository> lockRepository) {
|
||||
return lockRepository.<LockRegistry>map(JdbcLockRegistry::new).orElseGet(DefaultLockRegistry::new);
|
||||
return lockRepository.<LockRegistry> map(JdbcLockRegistry::new).orElseGet(DefaultLockRegistry::new);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -351,17 +309,6 @@ public class JpaRepositoryConfiguration {
|
||||
return e -> e instanceof TargetPollEvent && !repositoryProperties.isPublishTargetPollEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSetTypeManagement to loading the {@link DistributionSetType}
|
||||
* @param softwareManagement for loading {@link DistributionSet#getModules()}
|
||||
* @return DistributionSetBuilder bean
|
||||
*/
|
||||
@Bean
|
||||
DistributionSetBuilder distributionSetBuilder(final DistributionSetTypeManagement distributionSetTypeManagement,
|
||||
final SoftwareModuleManagement softwareManagement) {
|
||||
return new JpaDistributionSetBuilder(distributionSetTypeManagement, softwareManagement);
|
||||
}
|
||||
|
||||
@Bean
|
||||
TargetBuilder targetBuilder(final TargetTypeManagement targetTypeManagement) {
|
||||
return new JpaTargetBuilder(targetTypeManagement);
|
||||
@@ -378,30 +325,10 @@ public class JpaRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder(
|
||||
final SoftwareModuleManagement softwareModuleManagement) {
|
||||
final JpaSoftwareModuleManagement softwareModuleManagement) {
|
||||
return new JpaSoftwareModuleMetadataBuilder(softwareModuleManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareModuleTypeManagement for loading {@link DistributionSetType#getMandatoryModuleTypes()}
|
||||
* and {@link DistributionSetType#getOptionalModuleTypes()}
|
||||
* @return DistributionSetTypeBuilder bean
|
||||
*/
|
||||
@Bean
|
||||
DistributionSetTypeBuilder distributionSetTypeBuilder(
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
return new JpaDistributionSetTypeBuilder(softwareModuleTypeManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareModuleTypeManagement for loading {@link SoftwareModule#getType()}
|
||||
* @return SoftwareModuleBuilder bean
|
||||
*/
|
||||
@Bean
|
||||
SoftwareModuleBuilder softwareModuleBuilder(final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
return new JpaSoftwareModuleBuilder(softwareModuleTypeManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSetManagement for loading {@link Rollout#getDistributionSet()}
|
||||
* @return RolloutBuilder bean
|
||||
@@ -485,221 +412,6 @@ public class JpaRepositoryConfiguration {
|
||||
return new ExceptionMappingAspectHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default {@link BaseRepositoryTypeProvider} bean always provides the NoCountBaseRepository
|
||||
*
|
||||
* @return a {@link BaseRepositoryTypeProvider} bean
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
BaseRepositoryTypeProvider baseRepositoryTypeProvider() {
|
||||
return new HawkbitBaseRepository.RepositoryTypeProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaSystemManagement} bean.
|
||||
*
|
||||
* @return a new {@link SystemManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SystemManagement systemManagement(
|
||||
final TargetRepository targetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final TargetTagRepository targetTagRepository, final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final DistributionSetTagRepository distributionSetTagRepository, final RolloutRepository rolloutRepository,
|
||||
final TenantConfigurationRepository tenantConfigurationRepository, final TenantMetaDataRepository tenantMetaDataRepository,
|
||||
final TenantStatsManagement systemStatsManagement, final SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final PlatformTransactionManager txManager,
|
||||
final TenancyCacheManager cacheManager, final RolloutStatusCache rolloutStatusCache,
|
||||
final EntityManager entityManager, final RepositoryProperties repositoryProperties,
|
||||
final JpaProperties properties) {
|
||||
return new JpaSystemManagement(targetRepository, targetTypeRepository, targetTagRepository,
|
||||
targetFilterQueryRepository, softwareModuleRepository, softwareModuleTypeRepository, distributionSetRepository,
|
||||
distributionSetTypeRepository, distributionSetTagRepository, rolloutRepository, tenantConfigurationRepository,
|
||||
tenantMetaDataRepository, systemStatsManagement, currentTenantCacheKeyGenerator, systemSecurityContext,
|
||||
tenantAware, txManager, cacheManager, rolloutStatusCache, entityManager, repositoryProperties, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaDistributionSetManagement} bean.
|
||||
*
|
||||
* @return a new {@link DistributionSetManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DistributionSetManagement distributionSetManagement(
|
||||
final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetTagManagement distributionSetTagManagement, final SystemManagement systemManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final DistributionSetTagRepository distributionSetTagRepository, final RepositoryProperties repositoryProperties) {
|
||||
return new JpaDistributionSetManagement(entityManager, distributionSetRepository, distributionSetTagManagement,
|
||||
systemManagement, distributionSetTypeManagement, quotaManagement,
|
||||
targetRepository, targetFilterQueryRepository, actionRepository,
|
||||
TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement),
|
||||
softwareModuleRepository, distributionSetTagRepository, repositoryProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaDistributionSetManagement} bean.
|
||||
*
|
||||
* @return a new {@link DistributionSetManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DistributionSetTypeManagement distributionSetTypeManagement(
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final QuotaManagement quotaManagement) {
|
||||
return new JpaDistributionSetTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
|
||||
distributionSetRepository, targetTypeRepository, quotaManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaTargetTypeManagement} bean.
|
||||
*
|
||||
* @return a new {@link TargetTypeManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TargetTypeManagement targetTypeManagement(final TargetTypeRepository targetTypeRepository,
|
||||
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final QuotaManagement quotaManagement) {
|
||||
return new JpaTargetTypeManagement(targetTypeRepository, targetRepository, distributionSetTypeRepository, quotaManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaTenantStatsManagement} bean.
|
||||
*
|
||||
* @return a new {@link TenantStatsManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TenantStatsManagement tenantStatsManagement(
|
||||
final TargetRepository targetRepository, final LocalArtifactRepository artifactRepository, final ActionRepository actionRepository,
|
||||
final TenantAware tenantAware) {
|
||||
return new JpaTenantStatsManagement(targetRepository, artifactRepository, actionRepository, tenantAware);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaTenantConfigurationManagement} bean.
|
||||
*
|
||||
* @return a new {@link TenantConfigurationManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TenantConfigurationManagement tenantConfigurationManagement(
|
||||
final TenantConfigurationRepository tenantConfigurationRepository,
|
||||
final TenantConfigurationProperties tenantConfigurationProperties,
|
||||
final CacheManager cacheManager, final AfterTransactionCommitExecutor afterCommitExecutor,
|
||||
final ApplicationContext applicationContext) {
|
||||
return new JpaTenantConfigurationManagement(tenantConfigurationRepository, tenantConfigurationProperties,
|
||||
cacheManager, afterCommitExecutor, applicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaTargetManagement} bean.
|
||||
*
|
||||
* @return a new {@link JpaTargetManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TargetManagement targetManagement(
|
||||
final EntityManager entityManager, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
|
||||
final TenantAware tenantAware, final DistributionSetManagement distributionSetManagement) {
|
||||
return new JpaTargetManagement(entityManager, distributionSetManagement, quotaManagement, targetRepository,
|
||||
targetTypeRepository, rolloutGroupRepository, targetFilterQueryRepository,
|
||||
targetTagRepository, tenantAware);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaTargetFilterQueryManagement} bean.
|
||||
*
|
||||
* @param targetFilterQueryRepository holding {@link TargetFilterQuery} entities
|
||||
* @param targetManagement managing {@link Target} entities
|
||||
* @param distributionSetManagement for auto assign DS access
|
||||
* @param quotaManagement to access quotas
|
||||
* @return a new {@link TargetFilterQueryManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TargetFilterQueryManagement targetFilterQueryManagement(
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetManagement targetManagement,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final RepositoryProperties repositoryProperties,
|
||||
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware) {
|
||||
return new JpaTargetFilterQueryManagement(targetFilterQueryRepository, targetManagement,
|
||||
distributionSetManagement, quotaManagement, tenantConfigurationManagement, repositoryProperties,
|
||||
systemSecurityContext, contextAware, auditorAware);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaTargetTagManagement} bean.
|
||||
*
|
||||
* @return a new {@link TargetTagManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TargetTagManagement targetTagManagement(final TargetTagRepository targetTagRepository) {
|
||||
return new JpaTargetTagManagement(targetTagRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaDistributionSetTagManagement} bean.
|
||||
*
|
||||
* @return a new {@link JpaDistributionSetTagManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DistributionSetTagManagement distributionSetTagManagement(
|
||||
final DistributionSetTagRepository distributionSetTagRepository,
|
||||
final DistributionSetRepository distributionSetRepository) {
|
||||
return new JpaDistributionSetTagManagement(
|
||||
distributionSetTagRepository, distributionSetRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaSoftwareModuleManagement} bean.
|
||||
*
|
||||
* @return a new {@link SoftwareModuleManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SoftwareModuleManagement softwareModuleManagement(final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
|
||||
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
|
||||
return new JpaSoftwareModuleManagement(entityManager, distributionSetRepository, softwareModuleRepository,
|
||||
softwareModuleMetadataRepository, softwareModuleTypeRepository, auditorProvider, artifactManagement, quotaManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaSoftwareModuleTypeManagement} bean.
|
||||
*
|
||||
* @return a new {@link SoftwareModuleTypeManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SoftwareModuleTypeManagement softwareModuleTypeManagement(
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository) {
|
||||
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository, softwareModuleRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RolloutHandler rolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
|
||||
@@ -726,28 +438,6 @@ public class JpaRepositoryConfiguration {
|
||||
tenantAware, repositoryProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RolloutManagement rolloutManagement(
|
||||
final RolloutRepository rolloutRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final RolloutApprovalStrategy rolloutApprovalStrategy,
|
||||
final StartNextGroupRolloutGroupSuccessAction startNextRolloutGroupAction,
|
||||
final RolloutStatusCache rolloutStatusCache,
|
||||
final ActionRepository actionRepository,
|
||||
final TargetManagement targetManagement,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final QuotaManagement quotaManagement,
|
||||
final AfterTransactionCommitExecutor afterCommit,
|
||||
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
return new JpaRolloutManagement(rolloutRepository, rolloutGroupRepository, rolloutApprovalStrategy,
|
||||
startNextRolloutGroupAction, rolloutStatusCache, actionRepository, targetManagement,
|
||||
distributionSetManagement, tenantConfigurationManagement, quotaManagement, afterCommit,
|
||||
systemSecurityContext, contextAware, repositoryProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DefaultRolloutApprovalStrategy} bean.
|
||||
*
|
||||
@@ -758,90 +448,7 @@ public class JpaRepositoryConfiguration {
|
||||
RolloutApprovalStrategy rolloutApprovalStrategy(final UserAuthoritiesResolver userAuthoritiesResolver,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
return new DefaultRolloutApprovalStrategy(userAuthoritiesResolver, tenantConfigurationManagement,
|
||||
systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaRolloutGroupManagement} bean.
|
||||
*
|
||||
* @return a new {@link RolloutGroupManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RolloutGroupManagement rolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||
final TargetRepository targetRepository, final EntityManager entityManager, final RolloutStatusCache rolloutStatusCache) {
|
||||
return new JpaRolloutGroupManagement(rolloutGroupRepository, rolloutRepository, actionRepository,
|
||||
targetRepository, entityManager, rolloutStatusCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaDeploymentManagement} bean.
|
||||
*
|
||||
* @return a new {@link DeploymentManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DeploymentManagement deploymentManagement(final EntityManager entityManager,
|
||||
final ActionRepository actionRepository,
|
||||
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final AfterTransactionCommitExecutor afterCommit, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
|
||||
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
|
||||
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement, targetRepository, actionStatusRepository,
|
||||
auditorProvider,
|
||||
afterCommit, txManager, tenantConfigurationManagement,
|
||||
quotaManagement, systemSecurityContext, tenantAware, auditorAware, properties.getDatabase(), repositoryProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ConfirmationManagement confirmationManagement(final TargetRepository targetRepository,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
||||
final EntityManager entityManager, final EntityFactory entityFactory) {
|
||||
return new JpaConfirmationManagement(targetRepository, actionRepository, actionStatusRepository,
|
||||
repositoryProperties, quotaManagement, entityManager, entityFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaControllerManagement} bean.
|
||||
*
|
||||
* @return a new {@link ControllerManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ControllerManagement controllerManagement(
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository, final QuotaManagement quotaManagement,
|
||||
final RepositoryProperties repositoryProperties,
|
||||
final TargetRepository targetRepository, final TargetTypeManagement targetTypeManagement,
|
||||
final DeploymentManagement deploymentManagement, final ConfirmationManagement confirmationManagement,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final ControllerPollProperties controllerPollProperties,
|
||||
final PlatformTransactionManager txManager, final EntityFactory entityFactory, final EntityManager entityManager,
|
||||
final AfterTransactionCommitExecutor afterCommit,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware,
|
||||
final ScheduledExecutorService executorService) {
|
||||
return new JpaControllerManagement(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties,
|
||||
targetRepository, targetTypeManagement, deploymentManagement, confirmationManagement, softwareModuleRepository,
|
||||
softwareModuleMetadataRepository, distributionSetManagement, tenantConfigurationManagement, controllerPollProperties,
|
||||
txManager,entityFactory, entityManager, afterCommit, systemSecurityContext, tenantAware, executorService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ArtifactManagement artifactManagement(
|
||||
final EntityManager entityManager, final PlatformTransactionManager txManager,
|
||||
final LocalArtifactRepository localArtifactRepository, final SoftwareModuleRepository softwareModuleRepository,
|
||||
final Optional<ArtifactRepository> artifactRepository,
|
||||
final QuotaManagement quotaManagement, final TenantAware tenantAware) {
|
||||
return new JpaArtifactManagement(
|
||||
entityManager, txManager, localArtifactRepository, softwareModuleRepository, artifactRepository.orElse(null),
|
||||
quotaManagement, tenantAware);
|
||||
return new DefaultRolloutApprovalStrategy(userAuthoritiesResolver, tenantConfigurationManagement, systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -854,11 +461,11 @@ public class JpaRepositoryConfiguration {
|
||||
EntityFactory entityFactory(
|
||||
final TargetBuilder targetBuilder, final TargetTypeBuilder targetTypeBuilder,
|
||||
final TargetFilterQueryBuilder targetFilterQueryBuilder,
|
||||
final SoftwareModuleBuilder softwareModuleBuilder, final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder,
|
||||
final DistributionSetBuilder distributionSetBuilder, final DistributionSetTypeBuilder distributionSetTypeBuilder,
|
||||
final SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder,
|
||||
final RolloutBuilder rolloutBuilder) {
|
||||
return new JpaEntityFactory(targetBuilder, targetTypeBuilder, targetFilterQueryBuilder, softwareModuleBuilder,
|
||||
softwareModuleMetadataBuilder, distributionSetBuilder, distributionSetTypeBuilder, rolloutBuilder);
|
||||
return new JpaEntityFactory(
|
||||
targetBuilder, targetTypeBuilder, targetFilterQueryBuilder,
|
||||
softwareModuleMetadataBuilder, rolloutBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -976,7 +583,7 @@ public class JpaRepositoryConfiguration {
|
||||
RolloutScheduler rolloutScheduler(
|
||||
final SystemManagement systemManagement, final RolloutHandler rolloutHandler, final SystemSecurityContext systemSecurityContext,
|
||||
@Value("${hawkbit.rollout.executor.thread-pool.size:1}") final int threadPoolSize, final Optional<MeterRegistry> meterRegistry) {
|
||||
return new RolloutScheduler(rolloutHandler, systemManagement, systemSecurityContext, threadPoolSize, meterRegistry);
|
||||
return new RolloutScheduler(rolloutHandler, systemManagement, systemSecurityContext, threadPoolSize, meterRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -989,25 +596,6 @@ public class JpaRepositoryConfiguration {
|
||||
return RsqlUtility.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaDistributionSetInvalidationManagement} bean.
|
||||
*
|
||||
* @return a new {@link JpaDistributionSetInvalidationManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
JpaDistributionSetInvalidationManagement distributionSetInvalidationManagement(
|
||||
final DistributionSetManagement distributionSetManagement, final RolloutManagement rolloutManagement,
|
||||
final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final ActionRepository actionRepository,
|
||||
final PlatformTransactionManager txManager, final RepositoryProperties repositoryProperties,
|
||||
final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
return new JpaDistributionSetInvalidationManagement(distributionSetManagement, rolloutManagement,
|
||||
deploymentManagement, targetFilterQueryManagement, actionRepository, txManager, repositoryProperties,
|
||||
tenantAware, lockRegistry, systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default artifact encryption service bean that internally uses {@link ArtifactEncryption} and
|
||||
* {@link ArtifactEncryptionSecretsStore} beans for {@link SoftwareModule} artifacts encryption/decryption
|
||||
@@ -1019,4 +607,20 @@ public class JpaRepositoryConfiguration {
|
||||
ArtifactEncryptionService artifactEncryptionService() {
|
||||
return ArtifactEncryptionService.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
ManagementExceptionThrowingMethodAuthorizationDeniedHandler managementExceptionThrowingMethodAuthorizationDeniedHandler() {
|
||||
return new ManagementExceptionThrowingMethodAuthorizationDeniedHandler();
|
||||
}
|
||||
|
||||
public static class ManagementExceptionThrowingMethodAuthorizationDeniedHandler implements MethodAuthorizationDeniedHandler {
|
||||
|
||||
@Override
|
||||
public Object handleDeniedInvocation(final MethodInvocation methodInvocation, final AuthorizationResult authorizationResult) {
|
||||
throw ExceptionMapper.mapRe(
|
||||
authorizationResult instanceof AuthorizationDeniedException denied
|
||||
? denied
|
||||
: new AuthorizationDeniedException("Access Denied", authorizationResult));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,25 +9,13 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.aspects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.transaction.TransactionManager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.eclipse.hawkbit.exception.GenericSpServerException;
|
||||
import org.eclipse.hawkbit.repository.exception.ConcurrentModificationException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.transaction.TransactionSystemException;
|
||||
|
||||
/**
|
||||
* {@link Aspect} catches persistence exceptions and wraps them to custom
|
||||
@@ -38,27 +26,8 @@ import org.springframework.transaction.TransactionSystemException;
|
||||
@Aspect
|
||||
public class ExceptionMappingAspectHandler implements Ordered {
|
||||
|
||||
private static final Map<String, String> EXCEPTION_MAPPING = new HashMap<>(4);
|
||||
|
||||
/**
|
||||
* this is required to enable a certain order of exception and to select the most specific mappable exception according to the type
|
||||
* hierarchy of the exception.
|
||||
*/
|
||||
private static final List<Class<?>> MAPPED_EXCEPTION_ORDER = new ArrayList<>(4);
|
||||
|
||||
static {
|
||||
MAPPED_EXCEPTION_ORDER.add(DuplicateKeyException.class);
|
||||
MAPPED_EXCEPTION_ORDER.add(OptimisticLockingFailureException.class);
|
||||
MAPPED_EXCEPTION_ORDER.add(AccessDeniedException.class);
|
||||
|
||||
EXCEPTION_MAPPING.put(DuplicateKeyException.class.getName(), EntityAlreadyExistsException.class.getName());
|
||||
|
||||
EXCEPTION_MAPPING.put(OptimisticLockingFailureException.class.getName(), ConcurrentModificationException.class.getName());
|
||||
EXCEPTION_MAPPING.put(AccessDeniedException.class.getName(), InsufficientPermissionException.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* catch exceptions of the {@link TransactionManager} and wrap them to custom exceptions.
|
||||
* Catches exceptions of the {@link TransactionManager} and wrap them to custom exceptions.
|
||||
*
|
||||
* @param ex the thrown and catched exception
|
||||
* @throws Throwable
|
||||
@@ -68,48 +37,11 @@ public class ExceptionMappingAspectHandler implements Ordered {
|
||||
// It is a AspectJ proxy which deals with exceptions.
|
||||
@SuppressWarnings({ "squid:S00112", "squid:S1162" })
|
||||
public void catchAndWrapJpaExceptionsService(final Exception ex) throws Throwable {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Handling exception {}", ex.getClass().getName(), ex);
|
||||
} else {
|
||||
log.debug("Handling exception {}", ex.getClass().getName());
|
||||
}
|
||||
|
||||
// Workaround for EclipseLink merge where it does not throw ConstraintViolationException directly in case of existing entity update
|
||||
if (ex instanceof TransactionSystemException transactionSystemException) {
|
||||
throw replaceWithCauseIfConstraintViolationException(transactionSystemException);
|
||||
}
|
||||
|
||||
for (final Class<?> mappedEx : MAPPED_EXCEPTION_ORDER) {
|
||||
if (!mappedEx.isAssignableFrom(ex.getClass())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (EXCEPTION_MAPPING.containsKey(mappedEx.getName())) {
|
||||
throw (Exception) Class.forName(EXCEPTION_MAPPING.get(mappedEx.getName())).getConstructor(Throwable.class).newInstance(ex);
|
||||
}
|
||||
|
||||
log.error("there is no mapping configured for exception class {}", mappedEx.getName());
|
||||
throw new GenericSpServerException(ex);
|
||||
}
|
||||
|
||||
throw ex;
|
||||
throw ExceptionMapper.map(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static Exception replaceWithCauseIfConstraintViolationException(final TransactionSystemException rex) {
|
||||
Throwable exception = rex;
|
||||
do {
|
||||
final Throwable cause = exception.getCause();
|
||||
if (cause instanceof jakarta.validation.ConstraintViolationException) {
|
||||
return (Exception) cause;
|
||||
}
|
||||
exception = cause;
|
||||
} while (exception != null);
|
||||
|
||||
return rex;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link DistributionSet}.
|
||||
*/
|
||||
public class JpaDistributionSetBuilder implements DistributionSetBuilder {
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
public JpaDistributionSetBuilder(final DistributionSetTypeManagement distributionSetTypeManagement,
|
||||
final SoftwareModuleManagement softwareManagement) {
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.softwareModuleManagement = softwareManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetUpdate update(final long id) {
|
||||
return new GenericDistributionSetUpdate(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetCreate create() {
|
||||
return new JpaDistributionSetCreate(distributionSetTypeManagement, softwareModuleManagement);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.ValidString;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractDistributionSetUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Create/build implementation.
|
||||
*/
|
||||
public class JpaDistributionSetCreate extends AbstractDistributionSetUpdateCreate<DistributionSetCreate> implements DistributionSetCreate {
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
@Getter
|
||||
@ValidString
|
||||
private String type;
|
||||
|
||||
JpaDistributionSetCreate(
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final SoftwareModuleManagement softwareManagement) {
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.softwareModuleManagement = softwareManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetCreate type(final String type) {
|
||||
this.type = type.strip();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaDistributionSet build() {
|
||||
return new JpaDistributionSet(
|
||||
name, version, description,
|
||||
Optional.ofNullable(type).map(this::findDistributionSetTypeWithExceptionIfNotFound).orElse(null),
|
||||
findSoftwareModuleWithExceptionIfNotFound(modules),
|
||||
Optional.ofNullable(requiredMigrationStep).orElse(Boolean.FALSE));
|
||||
}
|
||||
|
||||
private DistributionSetType findDistributionSetTypeWithExceptionIfNotFound(final String distributionSetTypekey) {
|
||||
return distributionSetTypeManagement.findByKey(distributionSetTypekey)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, distributionSetTypekey));
|
||||
}
|
||||
|
||||
private Collection<SoftwareModule> findSoftwareModuleWithExceptionIfNotFound(final Collection<Long> softwareModuleIds) {
|
||||
if (CollectionUtils.isEmpty(softwareModuleIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Collection<SoftwareModule> modules = softwareModuleManagement.get(softwareModuleIds);
|
||||
if (modules.size() < softwareModuleIds.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, softwareModuleIds);
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericDistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link DistributionSetType}.
|
||||
*/
|
||||
public class JpaDistributionSetTypeBuilder implements DistributionSetTypeBuilder {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
public JpaDistributionSetTypeBuilder(final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetTypeUpdate update(final long id) {
|
||||
return new GenericDistributionSetTypeUpdate(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetTypeCreate create() {
|
||||
return new JpaDistributionSetTypeCreate(softwareModuleTypeManagement);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractDistributionSetTypeUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Create/build implementation.
|
||||
*/
|
||||
public class JpaDistributionSetTypeCreate extends AbstractDistributionSetTypeUpdateCreate<DistributionSetTypeCreate>
|
||||
implements DistributionSetTypeCreate {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
JpaDistributionSetTypeCreate(final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaDistributionSetType build() {
|
||||
final JpaDistributionSetType result = new JpaDistributionSetType(key, name, description, colour);
|
||||
|
||||
findSoftwareModuleTypeWithExceptionIfNotFound(mandatory).forEach(result::addMandatoryModuleType);
|
||||
findSoftwareModuleTypeWithExceptionIfNotFound(optional).forEach(result::addOptionalModuleType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<SoftwareModuleType> findSoftwareModuleTypeWithExceptionIfNotFound(
|
||||
final Collection<Long> softwareModuleTypeId) {
|
||||
if (CollectionUtils.isEmpty(softwareModuleTypeId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Collection<SoftwareModuleType> module = softwareModuleTypeManagement.get(softwareModuleTypeId);
|
||||
if (module.size() < softwareModuleTypeId.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModuleType.class, softwareModuleTypeId);
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link SoftwareModule}.
|
||||
*/
|
||||
public class JpaSoftwareModuleBuilder implements SoftwareModuleBuilder {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
public JpaSoftwareModuleBuilder(final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleUpdate update(final long id) {
|
||||
return new GenericSoftwareModuleUpdate(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleCreate create() {
|
||||
return new JpaSoftwareModuleCreate(softwareModuleTypeManagement);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractSoftwareModuleUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
|
||||
/**
|
||||
* Create/build implementation.
|
||||
*/
|
||||
public class JpaSoftwareModuleCreate extends AbstractSoftwareModuleUpdateCreate<SoftwareModuleCreate> implements SoftwareModuleCreate {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
private boolean encrypted;
|
||||
|
||||
JpaSoftwareModuleCreate(final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleCreate encrypted(final boolean encrypted) {
|
||||
this.encrypted = encrypted;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaSoftwareModule build() {
|
||||
return new JpaSoftwareModule(getSoftwareModuleTypeFromKeyString(type), name, version, description, vendor,
|
||||
encrypted);
|
||||
}
|
||||
|
||||
public boolean isEncrypted() {
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
private SoftwareModuleType getSoftwareModuleTypeFromKeyString(final String type) {
|
||||
if (type == null) {
|
||||
throw new ValidationException("type cannot be null");
|
||||
}
|
||||
|
||||
return softwareModuleTypeManagement.findByKey(type.trim())
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, type.trim()));
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
|
||||
/**
|
||||
@@ -21,9 +21,9 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
*/
|
||||
public class JpaSoftwareModuleMetadataBuilder implements SoftwareModuleMetadataBuilder {
|
||||
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
private final JpaSoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
public JpaSoftwareModuleMetadataBuilder(final SoftwareModuleManagement softwareModuleManagement) {
|
||||
public JpaSoftwareModuleMetadataBuilder(final JpaSoftwareModuleManagement softwareModuleManagement) {
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractSoftwareModuleMetadataUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
@@ -23,16 +24,16 @@ public class JpaSoftwareModuleMetadataCreate
|
||||
extends AbstractSoftwareModuleMetadataUpdateCreate<SoftwareModuleMetadataCreate>
|
||||
implements SoftwareModuleMetadataCreate {
|
||||
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
private final JpaSoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
JpaSoftwareModuleMetadataCreate(final long softwareModuleId, final SoftwareModuleManagement softwareModuleManagement) {
|
||||
JpaSoftwareModuleMetadataCreate(final long softwareModuleId, final JpaSoftwareModuleManagement softwareModuleManagement) {
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleId = softwareModuleId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaSoftwareModuleMetadata build() {
|
||||
final SoftwareModule module = softwareModuleManagement.get(softwareModuleId)
|
||||
final JpaSoftwareModule module = softwareModuleManagement.get(softwareModuleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
|
||||
if (key == null) {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link SoftwareModuleType}.
|
||||
*/
|
||||
public class JpaSoftwareModuleTypeBuilder implements SoftwareModuleTypeBuilder {
|
||||
|
||||
@Override
|
||||
public SoftwareModuleTypeUpdate update(final long id) {
|
||||
return new GenericSoftwareModuleTypeUpdate(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftwareModuleTypeCreate create() {
|
||||
return new JpaSoftwareModuleTypeCreate();
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractSoftwareModuleTypeUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
|
||||
/**
|
||||
* Create/build implementation.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class JpaSoftwareModuleTypeCreate extends AbstractSoftwareModuleTypeUpdateCreate<SoftwareModuleTypeCreate>
|
||||
implements SoftwareModuleTypeCreate {
|
||||
|
||||
@Override
|
||||
public JpaSoftwareModuleType build() {
|
||||
return new JpaSoftwareModuleType(key, name, description, maxAssignments, colour);
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,13 @@ import org.eclipse.hawkbit.repository.builder.GenericTagUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagUpdate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTag;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link Tag}.
|
||||
*/
|
||||
public class JpaTagBuilder implements TagBuilder {
|
||||
public class JpaTagBuilder implements TagBuilder<JpaTag> {
|
||||
|
||||
@Override
|
||||
public TagUpdate update(final long id) {
|
||||
@@ -26,7 +27,7 @@ public class JpaTagBuilder implements TagBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagCreate create() {
|
||||
public TagCreate<JpaTag> create() {
|
||||
return new JpaTagCreate();
|
||||
}
|
||||
}
|
||||
@@ -13,27 +13,21 @@ import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractTagUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
|
||||
/**
|
||||
* Create/build implementation.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class JpaTagCreate extends AbstractTagUpdateCreate<TagCreate> implements TagCreate {
|
||||
|
||||
public JpaDistributionSetTag buildDistributionSetTag() {
|
||||
return new JpaDistributionSetTag(name, description, colour);
|
||||
}
|
||||
public class JpaTagCreate extends AbstractTagUpdateCreate<TagCreate<JpaTag>> implements TagCreate<JpaTag> {
|
||||
|
||||
public JpaTargetTag buildTargetTag() {
|
||||
return new JpaTargetTag(name, description, colour);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag build() {
|
||||
public JpaTag build() {
|
||||
return new JpaTag(name, description, colour);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_DELAY;
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaUpdate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.Jpa;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaRepositoryConfiguration;
|
||||
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.repository.BaseEntityRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.utils.ObjectCopyUtil;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.security.authorization.method.HandleAuthorizationDenied;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link DistributionSetManagement}.
|
||||
*
|
||||
* @param <T> the JPA entity type
|
||||
* @param <C> the type of the create request
|
||||
* @param <U> the type of the update request
|
||||
* @param <R> the type of the entity JPA repository
|
||||
* @param <A> RSQL query field enum
|
||||
*/
|
||||
// Spring AOP doesn't support bridge methods and the AspectJ advices as ExceptionMappingAspectHandler could not handle the
|
||||
// thrown exception (e.g. to convert AuthorizationDeniedException to InsufficientPermissionException).
|
||||
// That's why we explictly handle the insufficient permission exception with this @HandleAuthorizationDenied annotation.
|
||||
@HandleAuthorizationDenied(handlerClass = JpaRepositoryConfiguration.ManagementExceptionThrowingMethodAuthorizationDeniedHandler.class)
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
abstract class AbstractJpaRepositoryManagement<T extends AbstractJpaBaseEntity, C, U extends Identifiable<Long>, R extends BaseEntityRepository<T>, A extends Enum<A> & RsqlQueryField>
|
||||
implements RepositoryManagement<T, C, U> {
|
||||
|
||||
public static final String DELETED = "deleted";
|
||||
|
||||
protected final R jpaRepository;
|
||||
protected final EntityManager entityManager;
|
||||
private final Constructor<T> entityConstructor;
|
||||
|
||||
protected AbstractJpaRepositoryManagement(final R jpaRepository, final EntityManager entityManager) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
this.entityManager = entityManager;
|
||||
try {
|
||||
entityConstructor = jpaRepository.getDomainClass().getConstructor();
|
||||
// test if method works, if fine - it shall never fail when called later
|
||||
entityConstructor.newInstance();
|
||||
} catch (final NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException("JPA domain class " + jpaRepository.getDomainClass() + " shall have public no-args constructor", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public T create(final C create) {
|
||||
return jpaRepository.save(AccessController.Operation.CREATE, jpaEntity(create));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public List<T> create(final Collection<C> create) {
|
||||
return jpaRepository.saveAll(AccessController.Operation.CREATE, create.stream().map(this::jpaEntity).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> get(final long id) {
|
||||
return jpaRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> get(final Collection<Long> ids) {
|
||||
return findAllById(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(final long id) {
|
||||
return jpaRepository.existsById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return jpaRepository.count(isNotDeleted().orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsql(String rsql) {
|
||||
return jpaRepository.count(JpaManagementHelper.combineWithAnd(rsqlSpec(rsql)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<T> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(
|
||||
jpaRepository, isNotDeleted().map(List::of).orElseGet(Collections::emptyList), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<T> findByRsql(final String rsql, final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, rsqlSpec(rsql), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
@SuppressWarnings("java:S1066") // javaS1066 - better readable that way
|
||||
public T update(final U update) {
|
||||
final T entity = jpaRepository
|
||||
.findById(update.getId())
|
||||
.orElseThrow(() -> new EntityNotFoundException(managementClass(), update.getId()));
|
||||
return update(update, entity);
|
||||
}
|
||||
|
||||
protected T update(final Identifiable<Long> update, final T entity) {
|
||||
// update getId has not setter in target JPA entity but shall have getter and the value shall be the same
|
||||
// otherwise the Utils will throw an exception that there is no counterpart setter for getId
|
||||
if (ObjectCopyUtil.copy(update, entity, false, this::attach)) {
|
||||
return jpaRepository.save(entity);
|
||||
} else { // otherwise it is not changed, so return the same entity
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void delete(final long id) {
|
||||
delete0(List.of(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
delete0(ids);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<Specification<T>> rsqlSpec(final String rsql) {
|
||||
return isNotDeleted()
|
||||
.map(isNotDeleted -> List.of(RsqlUtility.getInstance().<A, T> buildRsqlSpecification(rsql, fieldsClass()), isNotDeleted))
|
||||
.orElseGet(() -> List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, fieldsClass())));
|
||||
}
|
||||
|
||||
// return which are for soft deletion
|
||||
@SuppressWarnings("java:S1172") // java:S1172 - it is intended to be used by subclasses
|
||||
protected Collection<T> softDelete(final Collection<T> toDelete) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected void delete0(final Collection<Long> ids) {
|
||||
if (ObjectUtils.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<T> toDelete = findAllById(ids); // throws EntityNotFoundException if any of these does not exist
|
||||
jpaRepository.getAccessController().ifPresent(ac -> {
|
||||
for (final T entity : toDelete) {
|
||||
ac.assertOperationAllowed(AccessController.Operation.DELETE, entity);
|
||||
}
|
||||
});
|
||||
|
||||
// mark the rest as hard delete
|
||||
final Collection<Long> toSoftDelete = softDelete(toDelete).stream().map(T::getId).toList();
|
||||
if (!toSoftDelete.isEmpty()) {
|
||||
if (!supportSoftDelete()) {
|
||||
throw new IllegalStateException("Soft delete is not supported for " + jpaRepository.getDomainClass().getSimpleName());
|
||||
}
|
||||
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaUpdate<T> update = cb.createCriteriaUpdate(jpaRepository.getDomainClass());
|
||||
final Root<T> root = update.from(jpaRepository.getDomainClass());
|
||||
final CriteriaBuilder.In<Long> in = cb.in(root.get(AbstractJpaBaseEntity_.id));
|
||||
toSoftDelete.forEach(in::value);
|
||||
update.set(root.get(DELETED), true).where(in);
|
||||
entityManager.createQuery(update).executeUpdate();
|
||||
}
|
||||
|
||||
final List<Long> toHardDelete = toDelete.stream()
|
||||
.map(AbstractJpaBaseEntity::getId)
|
||||
.filter(id -> !toSoftDelete.contains(id))
|
||||
.toList();
|
||||
// hard delete the rest if exists
|
||||
if (!toHardDelete.isEmpty()) {
|
||||
// don't give the delete statement an empty list, JPA/Oracle cannot
|
||||
// handle the empty list
|
||||
jpaRepository.deleteAllById(toHardDelete);
|
||||
}
|
||||
}
|
||||
|
||||
private List<T> findAllById(final Collection<Long> ids) {
|
||||
final List<T> foundDs = jpaRepository.findAllById(ids);
|
||||
if (foundDs.size() != ids.size()) {
|
||||
throw new EntityNotFoundException(managementClass(), ids, foundDs.stream().map(T::getId).toList());
|
||||
}
|
||||
return foundDs;
|
||||
}
|
||||
|
||||
private final Supplier<Class<T>> managementClassSupplier = SingletonSupplier.of(this::managementClass0);
|
||||
|
||||
private Class<T> managementClass() {
|
||||
return managementClassSupplier.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<T> managementClass0() {
|
||||
return (Class<T>) jpaRepository.getManagementClass();
|
||||
}
|
||||
|
||||
private final Supplier<Class<A>> fieldsClassSupplier = SingletonSupplier.of(this::fieldsClass0);
|
||||
|
||||
private Class<A> fieldsClass() {
|
||||
return fieldsClassSupplier.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<A> fieldsClass0() {
|
||||
try {
|
||||
return (Class<A>) Class.forName("org.eclipse.hawkbit.repository." + managementClass().getSimpleName() + "Fields");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final Supplier<Boolean> supportSoftDeleteSupplier = SingletonSupplier.of(this::supportSoftDelete0);
|
||||
|
||||
private boolean supportSoftDelete() {
|
||||
return supportSoftDeleteSupplier.get();
|
||||
}
|
||||
|
||||
private boolean supportSoftDelete0() {
|
||||
return Stream.of(jpaRepository.getDomainClass().getDeclaredFields()).map(Field::getName).anyMatch(DELETED::equals);
|
||||
}
|
||||
|
||||
private final Supplier<Optional<Specification<T>>> isNotDeletedSupplier = SingletonSupplier.of(this::isNotDeleted0);
|
||||
|
||||
private Optional<Specification<T>> isNotDeleted() {
|
||||
return isNotDeletedSupplier.get();
|
||||
}
|
||||
|
||||
private Optional<Specification<T>> isNotDeleted0() {
|
||||
return supportSoftDelete()
|
||||
? Optional.of((root, query, cb) -> cb.equal(root.get(DELETED), false))
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private T jpaEntity(final Object create) {
|
||||
final T jpaEntity;
|
||||
try {
|
||||
jpaEntity = entityConstructor.newInstance();
|
||||
} catch (final InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException("Must NEVER happen!", e);
|
||||
}
|
||||
ObjectCopyUtil.copy(create, jpaEntity, false, this::attach);
|
||||
return jpaEntity;
|
||||
}
|
||||
|
||||
private Object attach(final Object propertyValue) {
|
||||
if (Jpa.JPA_VENDOR != Jpa.JpaVendor.HIBERNATE) {
|
||||
return propertyValue; // no need to attach, only Hibernate supports this
|
||||
}
|
||||
|
||||
if (propertyValue instanceof List<?> list) {
|
||||
return list.stream().map(this::attach).toList();
|
||||
} else if (propertyValue instanceof Set<?> set) {
|
||||
return set.stream().map(this::attach).collect(Collectors.toSet());
|
||||
} else if (propertyValue instanceof Map<?, ?> map) {
|
||||
return map.entrySet().stream().collect(Collectors.toMap(
|
||||
entry -> attach(entry.getKey()),
|
||||
entry -> attach(entry.getValue())));
|
||||
} else if (attachable(propertyValue)) {
|
||||
// hibernate require detached entities to be attached before setting to jpa entity as a sub-property
|
||||
return entityManager.merge(propertyValue);
|
||||
} else {
|
||||
return propertyValue; // no change
|
||||
}
|
||||
}
|
||||
|
||||
private boolean attachable(final Object propertyValue) {
|
||||
if (propertyValue == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Class<?> clazz = propertyValue.getClass();
|
||||
return !clazz.isPrimitive() && !clazz.isEnum() &&
|
||||
clazz != String.class && !Number.class.isAssignableFrom(clazz) && !Boolean.class.isAssignableFrom(clazz) &&
|
||||
!entityManager.contains(propertyValue); // no need to attach
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public class JpaActionManagement {
|
||||
protected final QuotaManagement quotaManagement;
|
||||
protected final RepositoryProperties repositoryProperties;
|
||||
|
||||
public JpaActionManagement(
|
||||
protected JpaActionManagement(
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository, final QuotaManagement quotaManagement,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
this.actionRepository = actionRepository;
|
||||
|
||||
@@ -51,11 +51,13 @@ import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -66,6 +68,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "artifact-management" }, matchIfMissing = true)
|
||||
public class JpaArtifactManagement implements ArtifactManagement {
|
||||
|
||||
private final EntityManager entityManager;
|
||||
@@ -77,7 +81,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
private final TenantAware tenantAware;
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
public JpaArtifactManagement(
|
||||
protected JpaArtifactManagement(
|
||||
final EntityManager entityManager,
|
||||
final PlatformTransactionManager txManager,
|
||||
final LocalArtifactRepository localArtifactRepository,
|
||||
|
||||
@@ -41,10 +41,11 @@ import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -56,15 +57,15 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "confirmation-management" }, matchIfMissing = true)
|
||||
public class JpaConfirmationManagement extends JpaActionManagement implements ConfirmationManagement {
|
||||
|
||||
public static final String CONFIRMATION_CODE_MSG_PREFIX = "Confirmation status code: %d";
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final EntityFactory entityFactory;
|
||||
private final TargetRepository targetRepository;
|
||||
|
||||
public JpaConfirmationManagement(
|
||||
protected JpaConfirmationManagement(
|
||||
final TargetRepository targetRepository,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
||||
|
||||
@@ -106,6 +106,7 @@ import org.eclipse.hawkbit.tenancy.configuration.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.PollingTime;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
@@ -116,6 +117,7 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -124,12 +126,11 @@ import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA based {@link ControllerManagement} implementation.
|
||||
*/
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "controller-management" }, matchIfMissing = true)
|
||||
public class JpaControllerManagement extends JpaActionManagement implements ControllerManagement {
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile("[a-zA-Z0-9_\\-!@#$%^&*()+=\\[\\]{}|;:'\",.<>/\\\\?\\s]*");
|
||||
@@ -143,10 +144,11 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
private final ConfirmationManagement confirmationManagement;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
private final SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final ControllerPollProperties controllerPollProperties;
|
||||
private final Duration minPollingTime, maxPollingTime;
|
||||
private final Duration minPollingTime;
|
||||
private final Duration maxPollingTime;
|
||||
private final PlatformTransactionManager txManager;
|
||||
private final EntityFactory entityFactory;
|
||||
private final EntityManager entityManager;
|
||||
@@ -155,13 +157,13 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
@SuppressWarnings("squid:S00107")
|
||||
public JpaControllerManagement(
|
||||
protected JpaControllerManagement(
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository, final QuotaManagement quotaManagement,
|
||||
final RepositoryProperties repositoryProperties,
|
||||
final TargetRepository targetRepository, final TargetTypeManagement targetTypeManagement,
|
||||
final DeploymentManagement deploymentManagement, final ConfirmationManagement confirmationManagement,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final ControllerPollProperties controllerPollProperties,
|
||||
final PlatformTransactionManager txManager, final EntityFactory entityFactory, final EntityManager entityManager,
|
||||
final AfterTransactionCommitExecutor afterCommit,
|
||||
|
||||
@@ -39,7 +39,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
@@ -89,6 +88,8 @@ import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -104,17 +105,17 @@ import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA implementation for {@link DeploymentManagement}.
|
||||
*/
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "deployment-management" }, matchIfMissing = true)
|
||||
public class JpaDeploymentManagement extends JpaActionManagement implements DeploymentManagement {
|
||||
|
||||
/**
|
||||
@@ -146,7 +147,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final JpaDistributionSetManagement distributionSetManagement;
|
||||
private final TargetRepository targetRepository;
|
||||
private final AuditorAware<String> auditorProvider;
|
||||
private final PlatformTransactionManager txManager;
|
||||
@@ -160,14 +161,14 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
private final RetryTemplate retryTemplate;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaDeploymentManagement(
|
||||
protected JpaDeploymentManagement(
|
||||
final EntityManager entityManager, final ActionRepository actionRepository,
|
||||
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||
final JpaDistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final AfterTransactionCommitExecutor afterCommit, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware<String> auditorAware,
|
||||
final Database database, final RepositoryProperties repositoryProperties) {
|
||||
final JpaProperties jpaProperties, final RepositoryProperties repositoryProperties) {
|
||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
@@ -184,7 +185,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.tenantAware = tenantAware;
|
||||
this.auditorAware = auditorAware;
|
||||
this.database = database;
|
||||
this.database = jpaProperties.getDatabase();
|
||||
this.retryTemplate = createRetryTemplate();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,16 +31,20 @@ import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.Cancelat
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.integration.support.locks.LockRegistry;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Jpa implementation for {@link DistributionSetInvalidationManagement}
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "distribution-set-invalidation-management" }, matchIfMissing = true)
|
||||
public class JpaDistributionSetInvalidationManagement implements DistributionSetInvalidationManagement {
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
|
||||
private final RolloutManagement rolloutManagement;
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
@@ -52,7 +56,7 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaDistributionSetInvalidationManagement(final DistributionSetManagement distributionSetManagement,
|
||||
protected JpaDistributionSetInvalidationManagement(final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||
final RolloutManagement rolloutManagement, final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final ActionRepository actionRepository,
|
||||
final PlatformTransactionManager txManager, final RepositoryProperties repositoryProperties,
|
||||
@@ -134,7 +138,7 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
throw new IncompleteDistributionSetException("Distribution set of type "
|
||||
+ distributionSet.getType().getKey() + " is incomplete: " + distributionSet.getId());
|
||||
}
|
||||
distributionSetManagement.invalidate(distributionSet);
|
||||
((DistributionSetManagement)distributionSetManagement).invalidate(distributionSet);
|
||||
log.debug("Distribution set {} marked as invalid.", setId);
|
||||
|
||||
// rollout cancellation should only be permitted with UPDATE_ROLLOUT permission
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_DELAY;
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX;
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.IMPLICIT_LOCK_ENABLED;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -37,10 +40,7 @@ import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.DeletedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
@@ -49,11 +49,10 @@ import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetExcepti
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
@@ -73,7 +72,9 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Statistic;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -81,229 +82,120 @@ import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link DistributionSetManagement}.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "distribution-set-management" }, matchIfMissing = true)
|
||||
public class JpaDistributionSetManagement
|
||||
extends AbstractJpaRepositoryManagement<JpaDistributionSet, DistributionSetManagement.Create, DistributionSetManagement.Update, DistributionSetRepository, DistributionSetFields>
|
||||
implements DistributionSetManagement<JpaDistributionSet> {
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
private final DistributionSetTagManagement distributionSetTagManagement;
|
||||
private final SystemManagement systemManagement;
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
private final DistributionSetTagManagement<JpaDistributionSetTag> distributionSetTagManagement;
|
||||
private final DistributionSetTypeManagement<JpaDistributionSetType> distributionSetTypeManagement;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
private final DistributionSetTagRepository distributionSetTagRepository;
|
||||
private final TargetRepository targetRepository;
|
||||
private final TargetFilterQueryRepository targetFilterQueryRepository;
|
||||
private final ActionRepository actionRepository;
|
||||
private final QuotaManagement quotaManagement;
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
private final DistributionSetTagRepository distributionSetTagRepository;
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaDistributionSetManagement(
|
||||
protected JpaDistributionSetManagement(
|
||||
final DistributionSetRepository jpaRepository,
|
||||
final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetTagManagement distributionSetTagManagement, final SystemManagement systemManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
|
||||
final TenantConfigHelper tenantConfigHelper,
|
||||
final DistributionSetTagManagement<JpaDistributionSetTag> distributionSetTagManagement,
|
||||
final DistributionSetTypeManagement<JpaDistributionSetType> distributionSetTypeManagement,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final DistributionSetTagRepository distributionSetTagRepository,
|
||||
final TargetRepository targetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final ActionRepository actionRepository,
|
||||
final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
super(jpaRepository, entityManager);
|
||||
this.distributionSetTagManagement = distributionSetTagManagement;
|
||||
this.systemManagement = systemManagement;
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
this.distributionSetTagRepository = distributionSetTagRepository;
|
||||
this.targetRepository = targetRepository;
|
||||
this.targetFilterQueryRepository = targetFilterQueryRepository;
|
||||
this.actionRepository = actionRepository;
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
this.distributionSetTagRepository = distributionSetTagRepository;
|
||||
this.quotaManagement = quotaManagement;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
|
||||
this.repositoryProperties = repositoryProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSet> create(final Collection<DistributionSetCreate> creates) {
|
||||
final List<JpaDistributionSet> toCreate = creates.stream().map(JpaDistributionSetCreate.class::cast)
|
||||
.map(this::setDefaultTypeIfMissing)
|
||||
.map(JpaDistributionSetCreate::build)
|
||||
.toList();
|
||||
return Collections.unmodifiableList(distributionSetRepository.saveAll(AccessController.Operation.CREATE, toCreate));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet create(final DistributionSetCreate c) {
|
||||
final JpaDistributionSetCreate create = (JpaDistributionSetCreate) c;
|
||||
setDefaultTypeIfMissing(create);
|
||||
return distributionSetRepository.save(AccessController.Operation.CREATE, create.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@SuppressWarnings("java:S1066") // javaS1066 - better readable that way
|
||||
public DistributionSet update(final DistributionSetUpdate u) {
|
||||
final GenericDistributionSetUpdate update = (GenericDistributionSetUpdate) u;
|
||||
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(update.getId());
|
||||
|
||||
update.getName().ifPresent(set::setName);
|
||||
update.getDescription().ifPresent(set::setDescription);
|
||||
update.getVersion().ifPresent(set::setVersion);
|
||||
public JpaDistributionSet update(final Update update) {
|
||||
final JpaDistributionSet distributionSet = getValid0(update.getId());
|
||||
|
||||
// lock/unlock ONLY if locked flag is present!
|
||||
if (Boolean.TRUE.equals(update.locked())) {
|
||||
if (!set.isLocked()) {
|
||||
lockSoftwareModules(set);
|
||||
set.lock();
|
||||
if (Boolean.TRUE.equals(update.getLocked())) {
|
||||
if (!distributionSet.isLocked()) {
|
||||
lockSoftwareModules(distributionSet);
|
||||
distributionSet.lock();
|
||||
}
|
||||
} else if (Boolean.FALSE.equals(update.locked())) {
|
||||
if (set.isLocked()) {
|
||||
set.unlock();
|
||||
} else if (Boolean.FALSE.equals(update.getLocked())) {
|
||||
if (distributionSet.isLocked()) {
|
||||
distributionSet.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (update.isRequiredMigrationStep() != null
|
||||
&& !update.isRequiredMigrationStep().equals(set.isRequiredMigrationStep())) {
|
||||
if (update.getRequiredMigrationStep() != null && !update.getRequiredMigrationStep().equals(distributionSet.isRequiredMigrationStep())) {
|
||||
assertDistributionSetIsNotAssignedToTargets(update.getId());
|
||||
set.setRequiredMigrationStep(update.isRequiredMigrationStep());
|
||||
}
|
||||
|
||||
return distributionSetRepository.save(set);
|
||||
return super.update(update, distributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long id) {
|
||||
delete0(List.of(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> distributionSetIDs) {
|
||||
delete0(distributionSetIDs);
|
||||
}
|
||||
private void delete0(final Collection<Long> distributionSetIDs) {
|
||||
getDistributionSets(distributionSetIDs); // throws EntityNotFoundException if any of these do not exists
|
||||
final List<JpaDistributionSet> setsFound = distributionSetRepository.findAll(
|
||||
AccessController.Operation.DELETE, distributionSetRepository.byIdsSpec(distributionSetIDs));
|
||||
if (setsFound.size() < distributionSetIDs.size()) {
|
||||
throw new InsufficientPermissionException("No DELETE access to some of distribution sets!");
|
||||
}
|
||||
|
||||
final List<Long> assigned = distributionSetRepository
|
||||
.findAssignedToTargetDistributionSetsById(distributionSetIDs);
|
||||
assigned.addAll(distributionSetRepository.findAssignedToRolloutDistributionSetsById(distributionSetIDs));
|
||||
|
||||
protected Collection<JpaDistributionSet> softDelete(final Collection<JpaDistributionSet> toDelete) {
|
||||
// soft delete assigned
|
||||
if (!assigned.isEmpty()) {
|
||||
distributionSetRepository.saveAll(
|
||||
setsFound.stream()
|
||||
.filter(set -> assigned.contains(set.getId()))
|
||||
.map(toSoftDelete -> {
|
||||
// don't use peek since it is by documentation mainly for debugging and could be skipped in some cases
|
||||
toSoftDelete.setDeleted(true);
|
||||
return toSoftDelete;
|
||||
})
|
||||
.toList());
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(assigned.toArray(new Long[0]));
|
||||
final List<Long> ids = toDelete.stream().map(JpaDistributionSet::getId).toList();
|
||||
final Set<Long> assigned = new HashSet<>(jpaRepository.findAssignedToTargetDistributionSetsById(ids));
|
||||
assigned.addAll(jpaRepository.findAssignedToRolloutDistributionSetsById(ids));
|
||||
return toDelete.stream().filter(distributionSet -> assigned.contains(distributionSet.getId())).toList();
|
||||
}
|
||||
|
||||
protected void delete0(final Collection<Long> distributionSetIDs) {
|
||||
if (ObjectUtils.isEmpty(distributionSetIDs)) {
|
||||
return; // super checks but if empty we don't want to unassign from target filters
|
||||
}
|
||||
|
||||
// mark the rest as hard delete
|
||||
final List<Long> toHardDelete = distributionSetIDs.stream().filter(setId -> !assigned.contains(setId)).toList();
|
||||
|
||||
// hard delete the rest if exists
|
||||
if (!toHardDelete.isEmpty()) {
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(
|
||||
toHardDelete.toArray(new Long[0]));
|
||||
// don't give the delete statement an empty list, JPA/Oracle cannot
|
||||
// handle the empty list
|
||||
distributionSetRepository.deleteAllById(toHardDelete);
|
||||
}
|
||||
// if delete fail (because of permission denied) transaction will be rolled back
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(distributionSetIDs.toArray(new Long[0]));
|
||||
super.delete0(distributionSetIDs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> get(final long id) {
|
||||
return distributionSetRepository.findById(id).map(DistributionSet.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DistributionSet> get(final Collection<Long> ids) {
|
||||
return Collections.unmodifiableList(getDistributionSets(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(final long id) {
|
||||
return distributionSetRepository.existsById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return distributionSetRepository.count(DistributionSetSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSet> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, List.of(
|
||||
DistributionSetSpecification.isNotDeleted()), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSet> findByRsql(final String rsql, final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class),
|
||||
DistributionSetSpecification.isNotDeleted()), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getWithDetails(final long id) {
|
||||
return distributionSetRepository
|
||||
.findOne(distributionSetRepository.byIdSpec(id), JpaDistributionSet_.GRAPH_DISTRIBUTION_SET_DETAIL)
|
||||
.map(DistributionSet.class::cast);
|
||||
public Optional<JpaDistributionSet> getWithDetails(final long id) {
|
||||
return jpaRepository.findOne(jpaRepository.byIdSpec(id), JpaDistributionSet_.GRAPH_DISTRIBUTION_SET_DETAIL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void invalidate(final DistributionSet distributionSet) {
|
||||
final JpaDistributionSet jpaSet = (JpaDistributionSet) distributionSet;
|
||||
jpaSet.invalidate();
|
||||
distributionSetRepository.save(jpaSet);
|
||||
public void invalidate(final JpaDistributionSet distributionSet) {
|
||||
distributionSet.invalidate();
|
||||
jpaRepository.save(distributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSet getOrElseThrowException(final long id) {
|
||||
public JpaDistributionSet getOrElseThrowException(final long id) {
|
||||
return getById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet assignSoftwareModules(final long id, final Collection<Long> softwareModuleId) {
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(id);
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public JpaDistributionSet assignSoftwareModules(final long id, final Collection<Long> softwareModuleId) {
|
||||
final JpaDistributionSet set = getValid0(id);
|
||||
assertDistributionSetIsNotAssignedToTargets(id);
|
||||
assertSoftwareModuleQuota(id, softwareModuleId.size());
|
||||
|
||||
@@ -315,47 +207,44 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
modules.forEach(set::addModule);
|
||||
|
||||
return distributionSetRepository.save(set);
|
||||
return jpaRepository.save(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet unassignSoftwareModule(final long id, final long moduleId) {
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(id);
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public JpaDistributionSet unassignSoftwareModule(final long id, final long moduleId) {
|
||||
final JpaDistributionSet set = getValid0(id);
|
||||
assertDistributionSetIsNotAssignedToTargets(id);
|
||||
|
||||
final JpaSoftwareModule module = findSoftwareModuleAndThrowExceptionIfNotFound(moduleId);
|
||||
set.removeModule(module);
|
||||
|
||||
return distributionSetRepository.save(set);
|
||||
return jpaRepository.save(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSet> assignTag(final Collection<Long> ids, final long dsTagId) {
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public List<JpaDistributionSet> assignTag(final Collection<Long> ids, final long dsTagId) {
|
||||
return updateTag(ids, dsTagId, (tag, distributionSet) -> {
|
||||
if (distributionSet.getTags().contains(tag)) {
|
||||
return distributionSet;
|
||||
} else {
|
||||
distributionSet.addTag(tag);
|
||||
return distributionSetRepository.save(distributionSet);
|
||||
return jpaRepository.save(distributionSet);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSet> unassignTag(final Collection<Long> ids, final long dsTagId) {
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public List<JpaDistributionSet> unassignTag(final Collection<Long> ids, final long dsTagId) {
|
||||
return updateTag(ids, dsTagId, (tag, distributionSet) -> {
|
||||
if (distributionSet.getTags().contains(tag)) {
|
||||
distributionSet.removeTag(tag);
|
||||
return distributionSetRepository.save(distributionSet);
|
||||
return jpaRepository.save(distributionSet);
|
||||
} else {
|
||||
return distributionSet;
|
||||
}
|
||||
@@ -364,10 +253,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void createMetadata(final long id, final Map<String, String> md) {
|
||||
final JpaDistributionSet distributionSet = (JpaDistributionSet) getValid(id);
|
||||
final JpaDistributionSet distributionSet = getValid0(id);
|
||||
|
||||
// get the modifiable metadata map
|
||||
final Map<String, String> metadata = distributionSet.getMetadata();
|
||||
@@ -380,7 +268,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
assertMetaDataQuota(id, metadata.size());
|
||||
|
||||
distributionSetRepository.save(distributionSet);
|
||||
jpaRepository.save(distributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -391,10 +279,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void updateMetadata(final long id, final String key, final String value) {
|
||||
final JpaDistributionSet distributionSet = (JpaDistributionSet) getValid(id);
|
||||
final JpaDistributionSet distributionSet = getValid0(id);
|
||||
|
||||
// get the modifiable metadata map
|
||||
final Map<String, String> metadata = distributionSet.getMetadata();
|
||||
@@ -403,15 +290,14 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
}
|
||||
metadata.put(key, value);
|
||||
|
||||
distributionSetRepository.save(distributionSet);
|
||||
jpaRepository.save(distributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void deleteMetadata(final long id, final String key) {
|
||||
final JpaDistributionSet distributionSet = (JpaDistributionSet) getValid(id);
|
||||
final JpaDistributionSet distributionSet = getValid0(id);
|
||||
|
||||
// get the modifiable metadata map
|
||||
final Map<String, String> metadata = distributionSet.getMetadata();
|
||||
@@ -419,68 +305,62 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
throw new EntityNotFoundException("DistributionSet metadata", id + ":" + key);
|
||||
}
|
||||
|
||||
distributionSetRepository.save(distributionSet);
|
||||
jpaRepository.save(distributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void lock(final long id) {
|
||||
final JpaDistributionSet distributionSet = getById(id);
|
||||
if (!distributionSet.isLocked()) {
|
||||
lockSoftwareModules(distributionSet);
|
||||
distributionSet.lock();
|
||||
distributionSetRepository.save(distributionSet);
|
||||
jpaRepository.save(distributionSet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void unlock(final long id) {
|
||||
final JpaDistributionSet distributionSet = getById(id);
|
||||
if (distributionSet.isLocked()) {
|
||||
distributionSet.unlock();
|
||||
distributionSetRepository.save(distributionSet);
|
||||
jpaRepository.save(distributionSet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> findByAction(final long actionId) {
|
||||
public Optional<JpaDistributionSet> findByAction(final long actionId) {
|
||||
return actionRepository
|
||||
.findById(actionId)
|
||||
.map(action -> {
|
||||
if (!targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId()))) {
|
||||
throw new InsufficientPermissionException("Target not accessible (or not found)!");
|
||||
}
|
||||
return distributionSetRepository
|
||||
return jpaRepository
|
||||
.findOne(DistributionSetSpecification.byIdFetch(action.getDistributionSet().getId()))
|
||||
.orElseThrow(() ->
|
||||
new InsufficientPermissionException("DistributionSet not accessible (or not found)!"));
|
||||
})
|
||||
.map(DistributionSet.class::cast)
|
||||
.or(() -> {
|
||||
throw new EntityNotFoundException(Action.class, actionId);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> findByNameAndVersion(final String distributionName, final String version) {
|
||||
return distributionSetRepository
|
||||
.findOne(DistributionSetSpecification.equalsNameAndVersionIgnoreCase(distributionName, version))
|
||||
.map(DistributionSet.class::cast);
|
||||
|
||||
public Optional<JpaDistributionSet> findByNameAndVersion(final String distributionName, final String version) {
|
||||
return jpaRepository.findOne(DistributionSetSpecification.equalsNameAndVersionIgnoreCase(distributionName, version));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSet getValidAndComplete(final long id) {
|
||||
final DistributionSet distributionSet = getValid(id);
|
||||
public JpaDistributionSet getValidAndComplete(final long id) {
|
||||
final JpaDistributionSet distributionSet = getValid0(id);
|
||||
|
||||
if (!distributionSet.isComplete()) {
|
||||
throw new IncompleteDistributionSetException("Distribution set of type "
|
||||
+ distributionSet.getType().getKey() + " is incomplete: " + distributionSet.getId());
|
||||
throw new IncompleteDistributionSetException(
|
||||
"Distribution set of type " + distributionSet.getType().getKey() + " is incomplete: " + distributionSet.getId());
|
||||
}
|
||||
|
||||
if (distributionSet.isDeleted()) {
|
||||
@@ -491,60 +371,49 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSet getValid(final long id) {
|
||||
final DistributionSet distributionSet = getOrElseThrowException(id);
|
||||
|
||||
if (!distributionSet.isValid()) {
|
||||
throw new InvalidDistributionSetException("Distribution set of type " + distributionSet.getType().getKey()
|
||||
+ " is invalid: " + distributionSet.getId());
|
||||
}
|
||||
|
||||
return distributionSet;
|
||||
public JpaDistributionSet getValid(final long id) {
|
||||
return getValid0(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSet> findByCompleted(final Boolean complete, final Pageable pageReq) {
|
||||
public Slice<JpaDistributionSet> findByCompleted(final Boolean complete, final Pageable pageReq) {
|
||||
final List<Specification<JpaDistributionSet>> specifications = buildSpecsByComplete(complete);
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, specifications, pageReq);
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(jpaRepository, specifications, pageReq);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByCompleted(final Boolean complete) {
|
||||
final List<Specification<JpaDistributionSet>> specifications = buildSpecsByComplete(complete);
|
||||
|
||||
return JpaManagementHelper.countBySpec(distributionSetRepository, specifications);
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, buildSpecsByComplete(complete));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSet> findByDistributionSetFilter(final DistributionSetFilter distributionSetFilter, final Pageable pageable) {
|
||||
final List<Specification<JpaDistributionSet>> specList = buildDistributionSetSpecifications(
|
||||
distributionSetFilter);
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, specList, pageable);
|
||||
public Slice<JpaDistributionSet> findByDistributionSetFilter(final DistributionSetFilter distributionSetFilter, final Pageable pageable) {
|
||||
final List<Specification<JpaDistributionSet>> specList = buildDistributionSetSpecifications(distributionSetFilter);
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(jpaRepository, specList, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByDistributionSetFilter(@NotNull final DistributionSetFilter distributionSetFilter) {
|
||||
final List<Specification<JpaDistributionSet>> specList = buildDistributionSetSpecifications(distributionSetFilter);
|
||||
return JpaManagementHelper.countBySpec(distributionSetRepository, specList);
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSet> findByTag(final long tagId, final Pageable pageable) {
|
||||
public Page<JpaDistributionSet> findByTag(final long tagId, final Pageable pageable) {
|
||||
assertDsTagExists(tagId);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of(
|
||||
DistributionSetSpecification.hasTag(tagId)), pageable);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, List.of(DistributionSetSpecification.hasTag(tagId)), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSet> findByRsqlAndTag(final String rsql, final long tagId, final Pageable pageable) {
|
||||
public Page<JpaDistributionSet> findByRsqlAndTag(final String rsql, final long tagId, final Pageable pageable) {
|
||||
assertDsTagExists(tagId);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class),
|
||||
DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isNotDeleted()), pageable);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(
|
||||
jpaRepository,
|
||||
List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class),
|
||||
DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isNotDeleted()),
|
||||
pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -552,37 +421,31 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
if (!distributionSetTypeManagement.exists(typeId)) {
|
||||
throw new EntityNotFoundException(DistributionSetType.class, typeId);
|
||||
}
|
||||
|
||||
return distributionSetRepository.count(DistributionSetSpecification.byType(typeId));
|
||||
return jpaRepository.count(DistributionSetSpecification.byType(typeId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInUse(final long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return actionRepository.countByDistributionSetId(id) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Statistic> countRolloutsByStatusForDistributionSet(final Long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetRepository.countRolloutsByStatusForDistributionSet(id).stream().map(Statistic.class::cast).toList();
|
||||
return jpaRepository.countRolloutsByStatusForDistributionSet(id).stream().map(Statistic.class::cast).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Statistic> countActionsByStatusForDistributionSet(final Long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetRepository.countActionsByStatusForDistributionSet(id).stream()
|
||||
.map(Statistic.class::cast).toList();
|
||||
return jpaRepository.countActionsByStatusForDistributionSet(id).stream().map(Statistic.class::cast).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countAutoAssignmentsForDistributionSet(final Long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetRepository.countAutoAssignmentsForDistributionSet(id);
|
||||
return jpaRepository.countAutoAssignmentsForDistributionSet(id);
|
||||
}
|
||||
|
||||
// check if it shall implicitly lock a distribution set
|
||||
@@ -619,40 +482,26 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
final DistributionSetFilter distributionSetFilter) {
|
||||
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>(10);
|
||||
|
||||
Specification<JpaDistributionSet> spec;
|
||||
|
||||
if (distributionSetFilter.getIsComplete() != null) {
|
||||
spec = DistributionSetSpecification.isCompleted(distributionSetFilter.getIsComplete());
|
||||
specList.add(spec);
|
||||
specList.add(DistributionSetSpecification.isCompleted(distributionSetFilter.getIsComplete()));
|
||||
}
|
||||
|
||||
if (distributionSetFilter.getIsDeleted() != null) {
|
||||
spec = DistributionSetSpecification.isDeleted(distributionSetFilter.getIsDeleted());
|
||||
specList.add(spec);
|
||||
specList.add(DistributionSetSpecification.isDeleted(distributionSetFilter.getIsDeleted()));
|
||||
}
|
||||
|
||||
if (distributionSetFilter.getIsValid() != null) {
|
||||
spec = DistributionSetSpecification.isValid(distributionSetFilter.getIsValid());
|
||||
specList.add(spec);
|
||||
specList.add(DistributionSetSpecification.isValid(distributionSetFilter.getIsValid()));
|
||||
}
|
||||
|
||||
if (distributionSetFilter.getTypeId() != null) {
|
||||
spec = DistributionSetSpecification.byType(distributionSetFilter.getTypeId());
|
||||
specList.add(spec);
|
||||
specList.add(DistributionSetSpecification.byType(distributionSetFilter.getTypeId()));
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(distributionSetFilter.getSearchText())) {
|
||||
final String[] dsFilterNameAndVersionEntries = JpaManagementHelper
|
||||
.getFilterNameAndVersionEntries(distributionSetFilter.getSearchText().trim());
|
||||
spec = DistributionSetSpecification.likeNameAndVersion(dsFilterNameAndVersionEntries[0],
|
||||
dsFilterNameAndVersionEntries[1]);
|
||||
specList.add(spec);
|
||||
specList.add(DistributionSetSpecification.likeNameAndVersion(dsFilterNameAndVersionEntries[0], dsFilterNameAndVersionEntries[1]));
|
||||
}
|
||||
|
||||
if (hasTagsFilterActive(distributionSetFilter)) {
|
||||
spec = DistributionSetSpecification.hasTags(distributionSetFilter.getTagNames(),
|
||||
distributionSetFilter.getSelectDSWithNoTag());
|
||||
specList.add(spec);
|
||||
specList.add(DistributionSetSpecification.hasTags(
|
||||
distributionSetFilter.getTagNames(), distributionSetFilter.getSelectDSWithNoTag()));
|
||||
}
|
||||
return specList;
|
||||
}
|
||||
@@ -660,7 +509,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
private static boolean hasTagsFilterActive(final DistributionSetFilter distributionSetFilter) {
|
||||
final boolean isNoTagActive = Boolean.TRUE.equals(distributionSetFilter.getSelectDSWithNoTag());
|
||||
final boolean isAtLeastOneTagActive = !CollectionUtils.isEmpty(distributionSetFilter.getTagNames());
|
||||
|
||||
return isNoTagActive || isAtLeastOneTagActive;
|
||||
}
|
||||
|
||||
@@ -670,16 +518,25 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
return distributionSetIds.stream().filter(id -> !foundDistributionSetMap.containsKey(id)).toList();
|
||||
}
|
||||
|
||||
private List<DistributionSet> updateTag(
|
||||
private JpaDistributionSet getValid0(final long id) {
|
||||
final JpaDistributionSet distributionSet = getById(id);
|
||||
if (!distributionSet.isValid()) {
|
||||
throw new InvalidDistributionSetException(
|
||||
"Distribution set of type " + distributionSet.getType().getKey() + " is invalid: " + distributionSet.getId());
|
||||
}
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
private List<JpaDistributionSet> updateTag(
|
||||
final Collection<Long> dsIds, final long dsTagId,
|
||||
final BiFunction<DistributionSetTag, JpaDistributionSet, DistributionSet> updater) {
|
||||
final BiFunction<DistributionSetTag, JpaDistributionSet, JpaDistributionSet> updater) {
|
||||
final DistributionSetTag tag = distributionSetTagManagement.get(dsTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, dsTagId));
|
||||
final List<JpaDistributionSet> allDs = dsIds.size() == 1 ?
|
||||
distributionSetRepository.findById(dsIds.iterator().next())
|
||||
jpaRepository.findById(dsIds.iterator().next())
|
||||
.map(List::of)
|
||||
.orElseGet(Collections::emptyList) :
|
||||
distributionSetRepository.findAll(DistributionSetSpecification.byIdsFetch(dsIds));
|
||||
jpaRepository.findAll(DistributionSetSpecification.byIdsFetch(dsIds));
|
||||
if (allDs.size() < dsIds.size()) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, notFound(dsIds, allDs));
|
||||
}
|
||||
@@ -716,13 +573,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
}
|
||||
|
||||
private JpaDistributionSetCreate setDefaultTypeIfMissing(final JpaDistributionSetCreate create) {
|
||||
if (create.getType() == null) {
|
||||
create.type(systemManagement.getTenantMetadata().getDefaultDsType().getKey());
|
||||
}
|
||||
return create;
|
||||
}
|
||||
|
||||
private List<Specification<JpaDistributionSet>> buildSpecsByComplete(final Boolean complete) {
|
||||
final List<Specification<JpaDistributionSet>> specifications = new ArrayList<>();
|
||||
specifications.add(DistributionSetSpecification.isNotDeleted());
|
||||
@@ -749,15 +599,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
}
|
||||
}
|
||||
|
||||
private List<JpaDistributionSet> getDistributionSets(final Collection<Long> ids) {
|
||||
final List<JpaDistributionSet> foundDs = distributionSetRepository.findAllById(ids);
|
||||
if (foundDs.size() != ids.size()) {
|
||||
throw new EntityNotFoundException(
|
||||
DistributionSet.class, ids, foundDs.stream().map(JpaDistributionSet::getId).toList());
|
||||
}
|
||||
return foundDs;
|
||||
}
|
||||
|
||||
private void lockSoftwareModules(final JpaDistributionSet distributionSet) {
|
||||
distributionSet.getModules().forEach(module -> {
|
||||
if (!module.isLocked()) {
|
||||
@@ -769,13 +610,13 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
}
|
||||
|
||||
private JpaDistributionSet getById(final long id) {
|
||||
return distributionSetRepository
|
||||
return jpaRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id));
|
||||
}
|
||||
|
||||
private void assertDistributionSetExists(final long id) {
|
||||
if (!distributionSetRepository.existsById(id)) {
|
||||
if (!jpaRepository.existsById(id)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,173 +9,73 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_DELAY;
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTagUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTagSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link TargetTagManagement}.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaDistributionSetTagManagement implements DistributionSetTagManagement {
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "distribution-set-tag-management" }, matchIfMissing = true)
|
||||
public class JpaDistributionSetTagManagement
|
||||
extends AbstractJpaRepositoryManagement<JpaDistributionSetTag, DistributionSetTagManagement.Create, DistributionSetTagManagement.Update, DistributionSetTagRepository, DistributionSetTagFields>
|
||||
implements DistributionSetTagManagement<JpaDistributionSetTag> {
|
||||
|
||||
private final DistributionSetTagRepository distributionSetTagRepository;
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
|
||||
public JpaDistributionSetTagManagement(
|
||||
protected JpaDistributionSetTagManagement(
|
||||
final DistributionSetTagRepository distributionSetTagRepository,
|
||||
final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository) {
|
||||
this.distributionSetTagRepository = distributionSetTagRepository;
|
||||
super(distributionSetTagRepository, entityManager);
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSetTag> create(final Collection<TagCreate> dst) {
|
||||
final List<JpaDistributionSetTag> toCreate = dst.stream()
|
||||
.map(JpaTagCreate.class::cast)
|
||||
.map(JpaTagCreate::buildDistributionSetTag)
|
||||
.toList();
|
||||
return Collections.unmodifiableList(distributionSetTagRepository.saveAll(AccessController.Operation.CREATE, toCreate));
|
||||
public Optional<JpaDistributionSetTag> findByName(final String name) {
|
||||
return jpaRepository.findByNameEquals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetTag create(final TagCreate c) {
|
||||
return distributionSetTagRepository.save(AccessController.Operation.CREATE, ((JpaTagCreate) c).buildDistributionSetTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetTag update(final TagUpdate u) {
|
||||
final GenericTagUpdate update = (GenericTagUpdate) u;
|
||||
final JpaDistributionSetTag tag = distributionSetTagRepository.findById(update.getId())
|
||||
.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
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long id) {
|
||||
distributionSetTagRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
final List<JpaDistributionSetTag> setsFound = distributionSetTagRepository.findAllById(ids);
|
||||
|
||||
if (setsFound.size() < ids.size()) {
|
||||
throw new EntityNotFoundException(
|
||||
DistributionSetTag.class, ids,
|
||||
setsFound.stream().map(DistributionSetTag::getId).toList());
|
||||
}
|
||||
|
||||
distributionSetTagRepository.deleteAll(setsFound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetTag> get(final long id) {
|
||||
return distributionSetTagRepository.findById(id).map(DistributionSetTag.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DistributionSetTag> get(final Collection<Long> ids) {
|
||||
return Collections.unmodifiableList(distributionSetTagRepository.findAllById(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(final long id) {
|
||||
return distributionSetTagRepository.existsById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return distributionSetTagRepository.count();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSetTag> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTagRepository, null, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetTag> findByRsql(final String rsql, final Pageable pageable) {
|
||||
final Specification<JpaDistributionSetTag> spec = RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetTagFields.class);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, Collections.singletonList(spec), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetTag> findByName(final String name) {
|
||||
return distributionSetTagRepository.findByNameEquals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetTag> findByDistributionSet(final long distributionSetId, final Pageable pageable) {
|
||||
public Page<JpaDistributionSetTag> findByDistributionSet(final long distributionSetId, final Pageable pageable) {
|
||||
if (!distributionSetRepository.existsById(distributionSetId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
||||
}
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository,
|
||||
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository,
|
||||
Collections.singletonList(TagSpecification.ofDistributionSet(distributionSetId)), pageable
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void delete(final String tagName) {
|
||||
final JpaDistributionSetTag dsTag = distributionSetTagRepository
|
||||
final JpaDistributionSetTag dsTag = jpaRepository
|
||||
.findOne(DistributionSetTagSpecifications.byName(tagName))
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName));
|
||||
distributionSetTagRepository.delete(dsTag);
|
||||
jpaRepository.delete(dsTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,29 +9,22 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_DELAY;
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericDistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
@@ -39,40 +32,35 @@ import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link DistributionSetTypeManagement}.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaDistributionSetTypeManagement implements DistributionSetTypeManagement {
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "distribution-set-type-management" }, matchIfMissing = true)
|
||||
public class JpaDistributionSetTypeManagement
|
||||
extends AbstractJpaRepositoryManagement<JpaDistributionSetType, DistributionSetTypeManagement.Create, DistributionSetTypeManagement.Update, DistributionSetTypeRepository, DistributionSetTypeFields>
|
||||
implements DistributionSetTypeManagement<JpaDistributionSetType> {
|
||||
|
||||
private final DistributionSetTypeRepository distributionSetTypeRepository;
|
||||
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
public JpaDistributionSetTypeManagement(
|
||||
protected JpaDistributionSetTypeManagement(
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final EntityManager entityManager,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final QuotaManagement quotaManagement) {
|
||||
this.distributionSetTypeRepository = distributionSetTypeRepository;
|
||||
super(distributionSetTypeRepository, entityManager);
|
||||
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.targetTypeRepository = targetTypeRepository;
|
||||
@@ -81,181 +69,62 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { 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(retryFor = { 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(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType update(final DistributionSetTypeUpdate u) {
|
||||
final GenericDistributionSetTypeUpdate update = (GenericDistributionSetTypeUpdate) u;
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(update.getId());
|
||||
update.getDescription().ifPresent(type::setDescription);
|
||||
update.getColour().ifPresent(type::setColour);
|
||||
|
||||
if (hasModuleChanges(update)) {
|
||||
checkDistributionSetTypeNotAssigned(update.getId());
|
||||
|
||||
final Collection<Long> currentMandatorySmTypeIds = type.getMandatoryModuleTypes().stream()
|
||||
.map(SoftwareModuleType::getId).collect(Collectors.toSet());
|
||||
final Collection<Long> currentOptionalSmTypeIds = type.getOptionalModuleTypes().stream()
|
||||
.map(SoftwareModuleType::getId).collect(Collectors.toSet());
|
||||
final Collection<Long> currentSmTypeIds = Stream
|
||||
.concat(currentMandatorySmTypeIds.stream(), currentOptionalSmTypeIds.stream())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final Collection<Long> updatedMandatorySmTypeIds = update.getMandatory().orElse(currentMandatorySmTypeIds);
|
||||
final Collection<Long> updatedOptionalSmTypeIds = update.getOptional().orElse(currentOptionalSmTypeIds);
|
||||
final Collection<Long> updatedSmTypeIds = Stream
|
||||
.concat(updatedMandatorySmTypeIds.stream(), updatedOptionalSmTypeIds.stream())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
addModuleTypes(currentMandatorySmTypeIds, updatedMandatorySmTypeIds, type::addMandatoryModuleType);
|
||||
addModuleTypes(currentOptionalSmTypeIds, updatedOptionalSmTypeIds, type::addOptionalModuleType);
|
||||
|
||||
removeModuleTypes(currentSmTypeIds, updatedSmTypeIds, type::removeModuleType);
|
||||
}
|
||||
|
||||
return distributionSetTypeRepository.save(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void delete(final long id) {
|
||||
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(id)
|
||||
final JpaDistributionSetType toDelete = jpaRepository.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, id));
|
||||
|
||||
unassignDsTypeFromTargetTypes(id);
|
||||
|
||||
if (distributionSetRepository.countByTypeId(id) > 0) {
|
||||
toDelete.setDeleted(true);
|
||||
distributionSetTypeRepository.save(AccessController.Operation.DELETE, toDelete);
|
||||
jpaRepository.save(AccessController.Operation.DELETE, toDelete);
|
||||
} else {
|
||||
distributionSetTypeRepository.deleteById(id);
|
||||
jpaRepository.deleteById(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
distributionSetTypeRepository.deleteAllById(ids);
|
||||
public void delete0(final Collection<Long> ids) {
|
||||
ids.forEach(this::unassignDsTypeFromTargetTypes);
|
||||
super.delete0(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> get(final long id) {
|
||||
return distributionSetTypeRepository.findById(id).map(DistributionSetType.class::cast);
|
||||
public Optional<JpaDistributionSetType> findByKey(final String key) {
|
||||
return jpaRepository.findOne(DistributionSetTypeSpecification.byKey(key));
|
||||
}
|
||||
|
||||
@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 long count() {
|
||||
return distributionSetTypeRepository.count(DistributionSetTypeSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSetType> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTypeRepository, List.of(
|
||||
DistributionSetTypeSpecification.isNotDeleted()), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetType> findByRsql(final String rsql, final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetTypeFields.class),
|
||||
DistributionSetTypeSpecification.isNotDeleted()), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> findByKey(final String key) {
|
||||
return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byKey(key)).map(DistributionSetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> findByName(final String name) {
|
||||
return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byName(name)).map(DistributionSetType.class::cast);
|
||||
public Optional<JpaDistributionSetType> findByName(final String name) {
|
||||
return jpaRepository.findOne(DistributionSetTypeSpecification.byName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType assignOptionalSoftwareModuleTypes(final long id, final Collection<Long> softwareModulesTypeIds) {
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public JpaDistributionSetType assignOptionalSoftwareModuleTypes(final long id, final Collection<Long> softwareModulesTypeIds) {
|
||||
return assignSoftwareModuleTypes(id, softwareModulesTypeIds, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType assignMandatorySoftwareModuleTypes(final long id, final Collection<Long> softwareModuleTypeIds) {
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public JpaDistributionSetType assignMandatorySoftwareModuleTypes(final long id, final Collection<Long> softwareModuleTypeIds) {
|
||||
return assignSoftwareModuleTypes(id, softwareModuleTypeIds, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType unassignSoftwareModuleType(final long id, final long softwareModuleTypeId) {
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public JpaDistributionSetType unassignSoftwareModuleType(final long id, final long softwareModuleTypeId) {
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(id);
|
||||
checkDistributionSetTypeNotAssigned(id);
|
||||
type.removeModuleType(softwareModuleTypeId);
|
||||
return distributionSetTypeRepository.save(type);
|
||||
type.removeModuleType(softwareModuleTypeRepository.getById(softwareModuleTypeId));
|
||||
return jpaRepository.save(type);
|
||||
}
|
||||
|
||||
private static void removeModuleTypes(
|
||||
final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
||||
final LongFunction<JpaDistributionSetType> removeModuleTypeCallback) {
|
||||
final Set<Long> smTypeIdsToRemove = currentSmTypeIds.stream().filter(id -> !updatedSmTypeIds.contains(id))
|
||||
.collect(Collectors.toSet());
|
||||
if (!CollectionUtils.isEmpty(smTypeIdsToRemove)) {
|
||||
smTypeIdsToRemove.forEach(removeModuleTypeCallback::apply);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasModuleChanges(final GenericDistributionSetTypeUpdate update) {
|
||||
return update.getOptional().isPresent() || update.getMandatory().isPresent();
|
||||
}
|
||||
|
||||
private void addModuleTypes(
|
||||
final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
||||
final Function<SoftwareModuleType, JpaDistributionSetType> addModuleTypeCallback) {
|
||||
final Set<Long> smTypeIdsToAdd = updatedSmTypeIds.stream().filter(id -> !currentSmTypeIds.contains(id)).collect(Collectors.toSet());
|
||||
if (!CollectionUtils.isEmpty(smTypeIdsToAdd)) {
|
||||
softwareModuleTypeRepository.findAllById(smTypeIdsToAdd).forEach(addModuleTypeCallback::apply);
|
||||
}
|
||||
}
|
||||
|
||||
private DistributionSetType assignSoftwareModuleTypes(
|
||||
private JpaDistributionSetType assignSoftwareModuleTypes(
|
||||
final long dsTypeId, final Collection<Long> softwareModulesTypeIds, final boolean mandatory) {
|
||||
final Collection<JpaSoftwareModuleType> foundModules = softwareModuleTypeRepository.findAllById(softwareModulesTypeIds);
|
||||
if (foundModules.size() < softwareModulesTypeIds.size()) {
|
||||
@@ -270,7 +139,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
foundModules.forEach(mandatory ? type::addMandatoryModuleType : type::addOptionalModuleType);
|
||||
|
||||
return distributionSetTypeRepository.save(type);
|
||||
return jpaRepository.save(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,7 +153,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
private void assertSoftwareModuleTypeQuota(final long id, final int requested) {
|
||||
QuotaHelper.assertAssignmentQuota(id, requested,
|
||||
quotaManagement.getMaxSoftwareModuleTypesPerDistributionSetType(), SoftwareModuleType.class,
|
||||
DistributionSetType.class, distributionSetTypeRepository::countSmTypesById);
|
||||
DistributionSetType.class, jpaRepository::countSmTypesById);
|
||||
}
|
||||
|
||||
private void unassignDsTypeFromTargetTypes(final long typeId) {
|
||||
@@ -295,8 +164,8 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
});
|
||||
}
|
||||
|
||||
private JpaDistributionSetType findDistributionSetTypeAndThrowExceptionIfNotFound(final Long setId) {
|
||||
return (JpaDistributionSetType) get(setId).orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, setId));
|
||||
private JpaDistributionSetType findDistributionSetTypeAndThrowExceptionIfNotFound(final Long id) {
|
||||
return jpaRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, id));
|
||||
}
|
||||
|
||||
private void checkDistributionSetTypeNotAssigned(final Long id) {
|
||||
|
||||
@@ -48,10 +48,12 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -61,6 +63,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
*/
|
||||
@Validated
|
||||
@Transactional(readOnly = true)
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "rollout-group-management" }, matchIfMissing = true)
|
||||
public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
|
||||
private final RolloutGroupRepository rolloutGroupRepository;
|
||||
@@ -71,7 +75,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
private final RolloutStatusCache rolloutStatusCache;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||
protected JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||
final TargetRepository targetRepository, final EntityManager entityManager, final RolloutStatusCache rolloutStatusCache) {
|
||||
this.rolloutGroupRepository = rolloutGroupRepository;
|
||||
|
||||
@@ -80,6 +80,7 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -89,6 +90,7 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -99,6 +101,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Slf4j
|
||||
@Validated
|
||||
@Transactional(readOnly = true)
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "rollout-management" }, matchIfMissing = true)
|
||||
public class JpaRolloutManagement implements RolloutManagement {
|
||||
|
||||
private static final List<RolloutStatus> ACTIVE_ROLLOUTS = List.of(
|
||||
@@ -123,8 +127,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
private final ContextAware contextAware;
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaRolloutManagement(
|
||||
protected JpaRolloutManagement(
|
||||
final RolloutRepository rolloutRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final RolloutApprovalStrategy rolloutApprovalStrategy,
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_DELAY;
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -21,25 +23,22 @@ import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.LockedException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
@@ -50,7 +49,6 @@ import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
@@ -58,8 +56,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -67,200 +65,121 @@ import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link SoftwareModuleManagement}.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "software-module-management" }, matchIfMissing = true)
|
||||
public class JpaSoftwareModuleManagement
|
||||
extends AbstractJpaRepositoryManagement<JpaSoftwareModule, SoftwareModuleManagement.Create, SoftwareModuleManagement.Update, SoftwareModuleRepository, SoftwareModuleFields>
|
||||
implements SoftwareModuleManagement<JpaSoftwareModule> {
|
||||
|
||||
protected static final String SOFTWARE_MODULE_METADATA = "SoftwareModuleMetadata";
|
||||
private final EntityManager entityManager;
|
||||
|
||||
private final SoftwareModuleTypeManagement<? extends SoftwareModuleType> softwareModuleTypeManagement;
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
private final SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
private final AuditorAware<String> auditorProvider;
|
||||
private final ArtifactManagement artifactManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaSoftwareModuleManagement(final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
protected JpaSoftwareModuleManagement(
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final EntityManager entityManager,
|
||||
final SoftwareModuleTypeManagement<? extends SoftwareModuleType> softwareModuleTypeManagement,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
|
||||
this.entityManager = entityManager;
|
||||
super(softwareModuleRepository, entityManager);
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
this.softwareModuleMetadataRepository = softwareModuleMetadataRepository;
|
||||
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
||||
this.auditorProvider = auditorProvider;
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<SoftwareModule> create(final Collection<SoftwareModuleCreate> swModules) {
|
||||
final List<JpaSoftwareModule> modulesToCreate = swModules.stream().map(JpaSoftwareModuleCreate.class::cast)
|
||||
.map(JpaSoftwareModuleCreate::build).toList();
|
||||
|
||||
final List<SoftwareModule> createdModules = Collections
|
||||
.unmodifiableList(softwareModuleRepository.saveAll(AccessController.Operation.CREATE, modulesToCreate));
|
||||
public List<JpaSoftwareModule> create(final Collection<Create> create) {
|
||||
final List<JpaSoftwareModule> createdModules = super.create(create);
|
||||
|
||||
if (createdModules.stream().anyMatch(SoftwareModule::isEncrypted)) {
|
||||
// flush sm creation in order to get ids
|
||||
entityManager.flush();
|
||||
createdModules.stream().filter(SoftwareModule::isEncrypted).map(SoftwareModule::getId)
|
||||
.forEach(encryptedModuleId -> ArtifactEncryptionService.getInstance()
|
||||
.addEncryptionSecrets(encryptedModuleId));
|
||||
createdModules.stream()
|
||||
.filter(SoftwareModule::isEncrypted)
|
||||
.map(SoftwareModule::getId)
|
||||
.forEach(encryptedModuleId -> ArtifactEncryptionService.getInstance().addEncryptionSecrets(encryptedModuleId));
|
||||
}
|
||||
|
||||
return createdModules;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public SoftwareModule create(final SoftwareModuleCreate c) {
|
||||
final JpaSoftwareModuleCreate create = (JpaSoftwareModuleCreate) c;
|
||||
public JpaSoftwareModule create(final Create create) {
|
||||
final JpaSoftwareModule createdModule = super.create(create);
|
||||
|
||||
final JpaSoftwareModule sm = softwareModuleRepository.save(AccessController.Operation.CREATE, create.build());
|
||||
if (create.isEncrypted()) {
|
||||
// flush sm creation in order to get an Id
|
||||
if (createdModule.isEncrypted()) {
|
||||
// flush sm creation in order to get an id
|
||||
entityManager.flush();
|
||||
ArtifactEncryptionService.getInstance().addEncryptionSecrets(sm.getId());
|
||||
ArtifactEncryptionService.getInstance().addEncryptionSecrets(createdModule.getId());
|
||||
}
|
||||
|
||||
return sm;
|
||||
return createdModule;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public SoftwareModule update(final SoftwareModuleUpdate u) {
|
||||
final GenericSoftwareModuleUpdate update = (GenericSoftwareModuleUpdate) u;
|
||||
|
||||
final JpaSoftwareModule module = softwareModuleRepository.findById(update.getId())
|
||||
public JpaSoftwareModule update(final Update update) {
|
||||
final JpaSoftwareModule module = jpaRepository.findById(update.getId())
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, update.getId()));
|
||||
|
||||
update.getDescription().ifPresent(module::setDescription);
|
||||
update.getVendor().ifPresent(module::setVendor);
|
||||
|
||||
// lock/unlock ONLY if locked flag is present!
|
||||
if (Boolean.TRUE.equals(update.locked())) {
|
||||
if (Boolean.TRUE.equals(update.getLocked())) {
|
||||
module.lock();
|
||||
} else if (Boolean.FALSE.equals(update.locked())) {
|
||||
} else if (Boolean.FALSE.equals(update.getLocked())) {
|
||||
module.unlock();
|
||||
}
|
||||
|
||||
return softwareModuleRepository.save(module);
|
||||
return super.update(update, module);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<JpaSoftwareModule> softDelete(final Collection<JpaSoftwareModule> toDelete) {
|
||||
return toDelete.stream()
|
||||
.filter(swModule -> {
|
||||
final List<DistributionSet> assignedTo = swModule.getAssignedTo();
|
||||
if (assignedTo != null) {
|
||||
final List<DistributionSet> lockedDS = assignedTo.stream()
|
||||
.filter(DistributionSet::isLocked)
|
||||
.filter(ds -> !ds.isDeleted())
|
||||
.toList();
|
||||
if (!lockedDS.isEmpty()) {
|
||||
final StringBuilder sb = new StringBuilder("Part of ");
|
||||
if (lockedDS.size() == 1) {
|
||||
sb.append("a locked distribution set: ");
|
||||
} else {
|
||||
sb.append(lockedDS.size()).append(" locked distribution sets: ");
|
||||
}
|
||||
for (final DistributionSet ds : lockedDS) {
|
||||
sb.append(ds.getName()).append(":").append(ds.getVersion()).append(" (").append(ds.getId()).append("), ");
|
||||
}
|
||||
sb.delete(sb.length() - 2, sb.length());
|
||||
throw new LockedException(JpaSoftwareModule.class, swModule.getId(), "DELETE", sb.toString());
|
||||
}
|
||||
}
|
||||
final boolean isAssigned = !ObjectUtils.isEmpty(assignedTo);
|
||||
// schedule delete binary data of artifacts for every soft or not soft deleted module
|
||||
deleteGridFsArtifacts(swModule);
|
||||
return isAssigned;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long id) {
|
||||
delete0(List.of(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
delete0(ids);
|
||||
}
|
||||
private void delete0(final Collection<Long> ids) {
|
||||
final List<JpaSoftwareModule> swModulesToDelete = softwareModuleRepository.findAllById(ids);
|
||||
if (swModulesToDelete.size() < ids.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, ids,
|
||||
swModulesToDelete.stream().map(SoftwareModule::getId).toList());
|
||||
}
|
||||
|
||||
final Set<Long> assignedModuleIds = new HashSet<>();
|
||||
swModulesToDelete.forEach(swModule -> {
|
||||
// execute this count operation without access limitations since we have to
|
||||
// ensure it's not assigned when deleting it.
|
||||
if (distributionSetRepository.countByModulesId(swModule.getId()) <= 0) {
|
||||
softwareModuleRepository.deleteById(swModule.getId());
|
||||
} else {
|
||||
assignedModuleIds.add(swModule.getId());
|
||||
}
|
||||
// schedule delete binary data of artifacts
|
||||
deleteGridFsArtifacts(swModule);
|
||||
});
|
||||
|
||||
if (!assignedModuleIds.isEmpty()) {
|
||||
String currentUser = null;
|
||||
if (auditorProvider != null) {
|
||||
currentUser = auditorProvider.getCurrentAuditor().orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO AC - could use single update query as before via entity manager directly (considers tenant!):
|
||||
maybe it will be possible, via specification when migrate to Spring Boot 3
|
||||
"UPDATE JpaSoftwareModule b SET b.deleted = 1, b.lastModifiedAt = :lastModifiedAt, b.lastModifiedBy = :lastModifiedBy WHERE b.tenant = :tenant AND b.id IN :ids"
|
||||
*/
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
final List<JpaSoftwareModule> toDelete = softwareModuleRepository.findAll(
|
||||
AccessController.Operation.DELETE, softwareModuleRepository.byIdsSpec(assignedModuleIds));
|
||||
for (final JpaSoftwareModule softwareModule : toDelete) {
|
||||
softwareModule.setDeleted(true);
|
||||
softwareModule.setLastModifiedAt(timestamp);
|
||||
softwareModule.setLastModifiedBy(currentUser);
|
||||
}
|
||||
softwareModuleRepository.saveAll(toDelete);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModule> get(final long id) {
|
||||
return softwareModuleRepository.findById(id).map(SoftwareModule.class::cast);
|
||||
}
|
||||
|
||||
@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 long count() {
|
||||
return softwareModuleRepository.count(SoftwareModuleSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModule> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, List.of(
|
||||
SoftwareModuleSpecification.isNotDeleted(),
|
||||
SoftwareModuleSpecification.fetchType()), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModule> findByRsql(final String rsql, final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, SoftwareModuleFields.class),
|
||||
SoftwareModuleSpecification.isNotDeleted()), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void createMetadata(final Collection<SoftwareModuleMetadataCreate> create) {
|
||||
// group by software module id to minimize database access
|
||||
create.stream()
|
||||
@@ -272,18 +191,16 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
|
||||
// touch to update revision and last modified timestamp
|
||||
JpaManagementHelper.touch(
|
||||
entityManager, softwareModuleRepository,
|
||||
(JpaSoftwareModule) get(id).orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
entityManager, jpaRepository, jpaRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
createsForSoftwareModule.forEach(this::saveMetadata);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public List<SoftwareModuleMetadata> getMetadata(final long id) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return (List)softwareModuleMetadataRepository.findAll(metadataBySoftwareModuleIdSpec(id));
|
||||
return (List) softwareModuleMetadataRepository.findAll(metadataBySoftwareModuleIdSpec(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -296,15 +213,13 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Override
|
||||
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(final long id, final Pageable pageable) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return JpaManagementHelper.convertPage(softwareModuleMetadataRepository.findBySoftwareModuleIdAndTargetVisible(
|
||||
id, true, PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT)), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public SoftwareModuleMetadata updateMetadata(final SoftwareModuleMetadataCreate c) {
|
||||
final JpaSoftwareModuleMetadataCreate create = (JpaSoftwareModuleMetadataCreate) c;
|
||||
final Long id = create.getSoftwareModuleId();
|
||||
@@ -314,15 +229,13 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
|
||||
// touch to update revision and last modified timestamp
|
||||
JpaManagementHelper.touch(
|
||||
entityManager, softwareModuleRepository,
|
||||
(JpaSoftwareModule) get(id).orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
entityManager, jpaRepository, jpaRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
return saveMetadata(create);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public SoftwareModuleMetadata updateMetadata(final SoftwareModuleMetadataUpdate u) {
|
||||
final GenericSoftwareModuleMetadataUpdate update = (GenericSoftwareModuleMetadataUpdate) u;
|
||||
|
||||
@@ -334,61 +247,59 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
update.getValue().ifPresent(metadata::setValue);
|
||||
update.isTargetVisible().ifPresent(metadata::setTargetVisible);
|
||||
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, metadata.getSoftwareModule());
|
||||
JpaManagementHelper.touch(entityManager, jpaRepository, metadata.getSoftwareModule());
|
||||
return softwareModuleMetadataRepository.save(metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void deleteMetadata(final long id, final String key) {
|
||||
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) findMetadata(id, key)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SOFTWARE_MODULE_METADATA, id + ":" + key));
|
||||
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, metadata.getSoftwareModule());
|
||||
JpaManagementHelper.touch(entityManager, jpaRepository, metadata.getSoftwareModule());
|
||||
softwareModuleMetadataRepository.deleteById(metadata.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void lock(final long id) {
|
||||
final JpaSoftwareModule softwareModule = softwareModuleRepository
|
||||
final JpaSoftwareModule softwareModule = jpaRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
if (!softwareModule.isLocked()) {
|
||||
softwareModule.lock();
|
||||
softwareModuleRepository.save(softwareModule);
|
||||
jpaRepository.save(softwareModule);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
public void unlock(final long id) {
|
||||
final JpaSoftwareModule softwareModule = softwareModuleRepository
|
||||
final JpaSoftwareModule softwareModule = jpaRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
if (softwareModule.isLocked()) {
|
||||
softwareModule.unlock();
|
||||
softwareModuleRepository.save(softwareModule);
|
||||
jpaRepository.save(softwareModule);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModule> findByAssignedTo(final long distributionSetId, final Pageable pageable) {
|
||||
public Page<JpaSoftwareModule> findByAssignedTo(final long distributionSetId, final Pageable pageable) {
|
||||
assertDistributionSetExists(distributionSetId);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository,
|
||||
Collections.singletonList(SoftwareModuleSpecification.byAssignedToDs(distributionSetId)), pageable
|
||||
);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(
|
||||
jpaRepository,
|
||||
Collections.singletonList(SoftwareModuleSpecification.byAssignedToDs(distributionSetId)),
|
||||
pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModule> findByTextAndType(final String searchText, final Long typeId, final Pageable pageable) {
|
||||
public Slice<JpaSoftwareModule> findByTextAndType(final String searchText, final Long typeId, final Pageable pageable) {
|
||||
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
|
||||
specList.add(SoftwareModuleSpecification.isNotDeleted());
|
||||
|
||||
@@ -403,30 +314,30 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
|
||||
specList.add(SoftwareModuleSpecification.fetchType());
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, specList, pageable);
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(jpaRepository, specList, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModule> findByNameAndVersionAndType(final String name, final String version,
|
||||
final long typeId) {
|
||||
public Optional<JpaSoftwareModule> findByNameAndVersionAndType(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);
|
||||
.findOneBySpec(
|
||||
jpaRepository,
|
||||
List.of(
|
||||
SoftwareModuleSpecification.likeNameAndVersion(name, version),
|
||||
SoftwareModuleSpecification.equalType(typeId),
|
||||
SoftwareModuleSpecification.fetchType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModule> findByType(final long typeId, final Pageable pageable) {
|
||||
public Slice<JpaSoftwareModule> findByType(final long typeId, final Pageable pageable) {
|
||||
assertSoftwareModuleTypeExists(typeId);
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(
|
||||
softwareModuleRepository,
|
||||
jpaRepository,
|
||||
List.of(
|
||||
SoftwareModuleSpecification.equalType(typeId),
|
||||
SoftwareModuleSpecification.isNotDeleted()), pageable
|
||||
@@ -445,7 +356,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
public long countByAssignedTo(final long distributionSetId) {
|
||||
assertDistributionSetExists(distributionSetId);
|
||||
|
||||
return softwareModuleRepository.count(SoftwareModuleSpecification.byAssignedToDs(distributionSetId));
|
||||
return jpaRepository.count(SoftwareModuleSpecification.byAssignedToDs(distributionSetId));
|
||||
}
|
||||
|
||||
private static Specification<JpaSoftwareModuleMetadata> metadataBySoftwareModuleIdSpec(final long id) {
|
||||
@@ -453,7 +364,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
}
|
||||
|
||||
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
||||
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
||||
jpaRepository.getAccessController().ifPresent(accessController ->
|
||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
||||
final Set<String> sha1Hashes = swModule.getArtifacts().stream().map(Artifact::getSha1Hash).collect(Collectors.toSet());
|
||||
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() ->
|
||||
@@ -499,7 +410,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleExists(final Long id) {
|
||||
if (!softwareModuleRepository.existsById(id)) {
|
||||
if (!jpaRepository.existsById(id)) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, id);
|
||||
}
|
||||
}
|
||||
@@ -515,4 +426,4 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,166 +10,52 @@
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link SoftwareModuleTypeManagement}.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManagement {
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "software-module-type=management" }, matchIfMissing = true)
|
||||
public class JpaSoftwareModuleTypeManagement
|
||||
extends AbstractJpaRepositoryManagement<JpaSoftwareModuleType, SoftwareModuleTypeManagement.Create, SoftwareModuleTypeManagement.Update, SoftwareModuleTypeRepository, SoftwareModuleTypeFields>
|
||||
implements SoftwareModuleTypeManagement<JpaSoftwareModuleType> {
|
||||
|
||||
private final DistributionSetTypeRepository distributionSetTypeRepository;
|
||||
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
public JpaSoftwareModuleTypeManagement(
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
protected JpaSoftwareModuleTypeManagement(
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final EntityManager entityManager,
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository) {
|
||||
super(softwareModuleTypeRepository, entityManager);
|
||||
this.distributionSetTypeRepository = distributionSetTypeRepository;
|
||||
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { 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());
|
||||
public Optional<JpaSoftwareModuleType> findByKey(final String key) {
|
||||
return jpaRepository.findByKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public SoftwareModuleType update(final SoftwareModuleTypeUpdate u) {
|
||||
final GenericSoftwareModuleTypeUpdate update = (GenericSoftwareModuleTypeUpdate) u;
|
||||
|
||||
final JpaSoftwareModuleType type = (JpaSoftwareModuleType) get(update.getId())
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, update.getId()));
|
||||
|
||||
update.getDescription().ifPresent(type::setDescription);
|
||||
update.getColour().ifPresent(type::setColour);
|
||||
|
||||
return softwareModuleTypeRepository.save(type);
|
||||
public Optional<JpaSoftwareModuleType> findByName(final String name) {
|
||||
return jpaRepository.findByName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long id) {
|
||||
final JpaSoftwareModuleType toDelete = softwareModuleTypeRepository.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, id));
|
||||
|
||||
delete(toDelete);
|
||||
protected Collection<JpaSoftwareModuleType> softDelete(final Collection<JpaSoftwareModuleType> toDelete) {
|
||||
return toDelete.stream().filter(smt ->
|
||||
softwareModuleRepository.countByType(smt) > 0 || distributionSetTypeRepository.countByElementsSmType(smt) > 0).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
softwareModuleTypeRepository
|
||||
.findAll(AccessController.Operation.DELETE, softwareModuleTypeRepository.byIdsSpec(ids))
|
||||
.forEach(this::delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModuleType> get(final long id) {
|
||||
return softwareModuleTypeRepository.findById(id).map(SoftwareModuleType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SoftwareModuleType> get(final Collection<Long> ids) {
|
||||
return Collections.unmodifiableList(softwareModuleTypeRepository.findAllById(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(final long id) {
|
||||
return softwareModuleTypeRepository.existsById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return softwareModuleTypeRepository.count(SoftwareModuleTypeSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModuleType> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleTypeRepository,
|
||||
List.of(SoftwareModuleTypeSpecification.isNotDeleted()), pageable
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModuleType> findByRsql(final String rsql, final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleTypeRepository, List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, SoftwareModuleTypeFields.class),
|
||||
SoftwareModuleTypeSpecification.isNotDeleted()), pageable
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModuleType> findByKey(final String key) {
|
||||
return softwareModuleTypeRepository.findByKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModuleType> findByName(final String name) {
|
||||
return softwareModuleTypeRepository.findByName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { 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));
|
||||
}
|
||||
|
||||
private void delete(JpaSoftwareModuleType toDelete) {
|
||||
if (softwareModuleRepository.countByType(toDelete) > 0
|
||||
|| distributionSetTypeRepository.countByElementsSmType(toDelete) > 0) {
|
||||
toDelete.setDeleted(true);
|
||||
softwareModuleTypeRepository.save(AccessController.Operation.DELETE, toDelete);
|
||||
} else {
|
||||
softwareModuleTypeRepository.delete(toDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,18 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.repository.artifact.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.cache.TenancyCacheManager;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.CurrentTenantCacheKeyGenerator;
|
||||
import org.eclipse.hawkbit.repository.jpa.SystemManagementCacheKeyGenerator;
|
||||
@@ -48,6 +49,7 @@ import org.eclipse.hawkbit.repository.report.model.SystemUsageReportWithTenants;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
@@ -58,6 +60,7 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -69,6 +72,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "system-management" }, matchIfMissing = true)
|
||||
public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement {
|
||||
|
||||
private static final int MAX_TENANTS_QUERY = 1000;
|
||||
@@ -102,7 +107,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
private ArtifactRepository artifactRepository;
|
||||
|
||||
@SuppressWarnings("squid:S00107")
|
||||
public JpaSystemManagement(
|
||||
protected JpaSystemManagement(
|
||||
final TargetRepository targetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final TargetTagRepository targetTagRepository, final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
@@ -193,6 +198,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
public void forEachTenant(final Consumer<String> consumer) {
|
||||
forEachTenant0(consumer);
|
||||
}
|
||||
|
||||
private void forEachTenant0(final Consumer<String> consumer) {
|
||||
Page<String> tenants;
|
||||
Pageable query = PageRequest.of(0, MAX_TENANTS_QUERY);
|
||||
@@ -320,18 +326,19 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
distributionSetTypeRepository
|
||||
.save(new JpaDistributionSetType(org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_OS_ONLY_KEY,
|
||||
org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_OS_ONLY_NAME,
|
||||
"Default type with Firmware/OS only.").addMandatoryModuleType(os));
|
||||
"Default type with Firmware/OS only.").setMandatoryModuleTypes(Set.of(os)));
|
||||
|
||||
distributionSetTypeRepository
|
||||
.save(new JpaDistributionSetType(org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_APP_ONLY_KEY,
|
||||
org.eclipse.hawkbit.repository.Constants.DST_DEFAULT_APP_ONLY_NAME,
|
||||
"Default type with app(s) only.").addMandatoryModuleType(app));
|
||||
"Default type with app(s) only.").setMandatoryModuleTypes(Set.of(app)));
|
||||
|
||||
return distributionSetTypeRepository
|
||||
.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,
|
||||
"Default type with Firmware/OS and optional app(s).").addMandatoryModuleType(os)
|
||||
.addOptionalModuleType(app));
|
||||
"Default type with Firmware/OS and optional app(s).")
|
||||
.setMandatoryModuleTypes(Set.of(os))
|
||||
.setOptionalModuleTypes(Set.of(app)));
|
||||
}
|
||||
|
||||
private TenantMetaData createTenantMetadata0(final String tenant) {
|
||||
|
||||
@@ -52,6 +52,7 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -60,6 +61,7 @@ import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -70,11 +72,13 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaTargetFilterQueryManagement implements TargetFilterQueryManagement {
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "target-filter-management" }, matchIfMissing = true)
|
||||
class JpaTargetFilterQueryManagement implements TargetFilterQueryManagement {
|
||||
|
||||
private final TargetFilterQueryRepository targetFilterQueryRepository;
|
||||
private final TargetManagement targetManagement;
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
@@ -82,10 +86,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
private final ContextAware contextAware;
|
||||
private final AuditorAware<String> auditorAware;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaTargetFilterQueryManagement(
|
||||
protected JpaTargetFilterQueryManagement(
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
|
||||
final TargetManagement targetManagement, final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||
final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final RepositoryProperties repositoryProperties,
|
||||
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware<String> auditorAware) {
|
||||
|
||||
@@ -77,6 +77,7 @@ import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -84,6 +85,7 @@ import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -93,10 +95,12 @@ import org.springframework.validation.annotation.Validated;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "target-management" }, matchIfMissing = true)
|
||||
public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final JpaDistributionSetManagement distributionSetManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
private final TargetRepository targetRepository;
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
@@ -106,8 +110,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
public JpaTargetManagement(final EntityManager entityManager,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
protected JpaTargetManagement(final EntityManager entityManager,
|
||||
final JpaDistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
|
||||
@@ -28,12 +28,15 @@ import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@@ -42,11 +45,13 @@ import org.springframework.validation.annotation.Validated;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "target-tag-management" }, matchIfMissing = true)
|
||||
public class JpaTargetTagManagement implements TargetTagManagement {
|
||||
|
||||
private final TargetTagRepository targetTagRepository;
|
||||
|
||||
public JpaTargetTagManagement(final TargetTagRepository targetTagRepository) {
|
||||
protected JpaTargetTagManagement(final TargetTagRepository targetTagRepository) {
|
||||
this.targetTagRepository = targetTagRepository;;
|
||||
}
|
||||
|
||||
@@ -69,7 +74,7 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<TargetTag> create(final Collection<TagCreate> tt) {
|
||||
public List<TargetTag> create(final Collection<TagCreate<Tag>> tt) {
|
||||
final List<JpaTargetTag> targetTagList = tt.stream().map(JpaTagCreate.class::cast)
|
||||
.map(JpaTagCreate::buildTargetTag).toList();
|
||||
return Collections.unmodifiableList(
|
||||
|
||||
@@ -38,12 +38,14 @@ import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@@ -52,6 +54,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "target-type-management" }, matchIfMissing = true)
|
||||
public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
@@ -60,13 +64,7 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param targetTypeRepository Target type repository
|
||||
* @param targetRepository Target repository
|
||||
*/
|
||||
public JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository,
|
||||
protected JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository,
|
||||
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final QuotaManagement quotaManagement) {
|
||||
this.targetTypeRepository = targetTypeRepository;
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.eclipse.hawkbit.tenancy.configuration.PollingTime;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
@@ -65,6 +66,7 @@ import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -75,6 +77,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "tenant-configuration-management" }, matchIfMissing = true)
|
||||
public class JpaTenantConfigurationManagement implements TenantConfigurationManagement {
|
||||
|
||||
private static final ConfigurableConversionService CONVERSION_SERVICE = new DefaultConversionService();
|
||||
@@ -87,7 +91,7 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
||||
|
||||
private ServiceMatcher serviceMatcher;
|
||||
|
||||
public JpaTenantConfigurationManagement(
|
||||
protected JpaTenantConfigurationManagement(
|
||||
final TenantConfigurationRepository tenantConfigurationRepository,
|
||||
final TenantConfigurationProperties tenantConfigurationProperties,
|
||||
final CacheManager cacheManager, final AfterTransactionCommitExecutor afterCommitExecutor,
|
||||
|
||||
@@ -15,6 +15,8 @@ import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -23,6 +25,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
* Management service for statistics of a single tenant.
|
||||
*/
|
||||
@Validated
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "tenant-stats-management" }, matchIfMissing = true)
|
||||
public class JpaTenantStatsManagement implements TenantStatsManagement {
|
||||
|
||||
private final TargetRepository targetRepository;
|
||||
@@ -30,7 +34,7 @@ public class JpaTenantStatsManagement implements TenantStatsManagement {
|
||||
private final ActionRepository actionRepository;
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
public JpaTenantStatsManagement(
|
||||
protected JpaTenantStatsManagement(
|
||||
final TargetRepository targetRepository, final LocalArtifactRepository artifactRepository, final ActionRepository actionRepository,
|
||||
final TenantAware tenantAware) {
|
||||
this.targetRepository = targetRepository;
|
||||
|
||||
@@ -40,10 +40,9 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
||||
|
||||
/**
|
||||
* AbstractDsAssignmentStrategy for offline assignments, i.e. not managed by
|
||||
* hawkBit.
|
||||
* AbstractDsAssignmentStrategy for offline assignments, i.e. not managed by hawkBit.
|
||||
*/
|
||||
public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
|
||||
OfflineDsAssignmentStrategy(
|
||||
final TargetRepository targetRepository,
|
||||
|
||||
@@ -48,7 +48,7 @@ import org.springframework.util.CollectionUtils;
|
||||
/**
|
||||
* AbstractDsAssignmentStrategy for online assignments, i.e. managed by hawkBit.
|
||||
*/
|
||||
public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
|
||||
OnlineDsAssignmentStrategy(final TargetRepository targetRepository,
|
||||
final AfterTransactionCommitExecutor afterCommit,
|
||||
|
||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ConstraintMode;
|
||||
@@ -85,28 +86,13 @@ public class DistributionSetTypeElement implements Serializable {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (key == null ? 0 : key.hashCode());
|
||||
return result;
|
||||
return Objects.hash(key, mandatory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DistributionSetTypeElement other = (DistributionSetTypeElement) obj;
|
||||
if (key == null) {
|
||||
return other.key == null;
|
||||
} else {
|
||||
return key.equals(other.key);
|
||||
}
|
||||
return obj instanceof DistributionSetTypeElement distributionSetTypeElement &&
|
||||
Objects.equals(key, distributionSetTypeElement.key) &&
|
||||
Objects.equals(mandatory, distributionSetTypeElement.mandatory);
|
||||
}
|
||||
}
|
||||
@@ -137,35 +137,22 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
@Column(name = "required_migration_step")
|
||||
private boolean requiredMigrationStep;
|
||||
|
||||
public JpaDistributionSet(
|
||||
final String name, final String version, final String description,
|
||||
final DistributionSetType type, final Collection<SoftwareModule> moduleList,
|
||||
final boolean requiredMigrationStep) {
|
||||
super(name, version, description);
|
||||
|
||||
this.type = type;
|
||||
// modules shall be set before type.checkComplete call
|
||||
if (moduleList != null) {
|
||||
moduleList.forEach(this::addModule);
|
||||
}
|
||||
if (this.type != null) {
|
||||
complete = this.type.checkComplete(this);
|
||||
}
|
||||
|
||||
this.valid = true;
|
||||
this.requiredMigrationStep = requiredMigrationStep;
|
||||
}
|
||||
|
||||
public JpaDistributionSet(final String name, final String version, final String description,
|
||||
final DistributionSetType type, final Collection<SoftwareModule> moduleList) {
|
||||
this(name, version, description, type, moduleList, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SoftwareModule> getModules() {
|
||||
return Collections.unmodifiableSet(modules);
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S1144") // used via reflection copy utils
|
||||
private JpaDistributionSet setModules(final Set<SoftwareModule> modules) {
|
||||
if (modules == null) {
|
||||
return this; // do not change
|
||||
}
|
||||
|
||||
modules.forEach(this::addModule); // skip if already present
|
||||
this.modules.stream().filter(module -> !modules.contains(module)).toList().forEach(this::removeModule);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addModule(final SoftwareModule softwareModule) {
|
||||
if (isLocked()) {
|
||||
throw new LockedException(JpaDistributionSet.class, getId(), "ADD_SOFTWARE_MODULE");
|
||||
@@ -175,13 +162,11 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
|
||||
final Optional<SoftwareModule> found = modules.stream()
|
||||
.filter(module -> module.getId().equals(softwareModule.getId())).findAny();
|
||||
|
||||
if (found.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final long already = modules.stream().filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count();
|
||||
|
||||
if (already >= softwareModule.getType().getMaxAssignments()) {
|
||||
modules.stream().filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey()))
|
||||
.findAny().ifPresent(modules::remove);
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
@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_prim", columnList = "tenant,id") }, uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = { "tenant", "type_key"}, name = "uk_sp_distribution_set_type_type_key"),
|
||||
@UniqueConstraint(columnNames = { "tenant", "type_key" }, name = "uk_sp_distribution_set_type_type_key"),
|
||||
@UniqueConstraint(columnNames = { "tenant", "name" }, name = "uk_sp_distribution_set_type_name") })
|
||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for sub entities
|
||||
@SuppressWarnings("squid:S2160")
|
||||
@@ -88,6 +88,30 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public JpaDistributionSetType setMandatoryModuleTypes(final Set<SoftwareModuleType> smType) {
|
||||
return replaceOrAddModuleTypes(smType, true, true);
|
||||
}
|
||||
|
||||
public JpaDistributionSetType setOptionalModuleTypes(final Set<SoftwareModuleType> smType) {
|
||||
return replaceOrAddModuleTypes(smType, false, true);
|
||||
}
|
||||
|
||||
public JpaDistributionSetType addMandatoryModuleType(final SoftwareModuleType smType) {
|
||||
return replaceOrAddModuleTypes(Set.of(smType), true, false);
|
||||
}
|
||||
|
||||
public JpaDistributionSetType addOptionalModuleType(final SoftwareModuleType smType) {
|
||||
return replaceOrAddModuleTypes(Set.of(smType), false, false);
|
||||
}
|
||||
|
||||
public JpaDistributionSetType removeModuleType(final SoftwareModuleType smType) {
|
||||
elements.stream()
|
||||
.filter(element -> smType.getId().equals(element.getSmType().getId()))
|
||||
.toList() // collect to a list to avoid ConcurrentModificationException
|
||||
.forEach(element -> elements.remove(element));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkComplete(final DistributionSet distributionSet) {
|
||||
final List<SoftwareModuleType> smTypes = distributionSet.getModules().stream()
|
||||
@@ -97,23 +121,6 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
||||
return !smTypes.isEmpty() && new HashSet<>(smTypes).containsAll(getMandatoryModuleTypes());
|
||||
}
|
||||
|
||||
public JpaDistributionSetType addOptionalModuleType(final SoftwareModuleType smType) {
|
||||
return setModuleType(smType, false);
|
||||
}
|
||||
|
||||
public JpaDistributionSetType addMandatoryModuleType(final SoftwareModuleType smType) {
|
||||
return setModuleType(smType, true);
|
||||
}
|
||||
|
||||
public JpaDistributionSetType removeModuleType(final Long smTypeId) {
|
||||
// we search by id (standard equals compares also revision)
|
||||
elements.stream()
|
||||
.filter(element -> element.getSmType().getId().equals(smTypeId))
|
||||
.findAny()
|
||||
.ifPresent(elements::remove);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DistributionSetType [key=" + getKey() + ", isDeleted()=" + isDeleted() + ", getId()=" + getId() + "]";
|
||||
@@ -135,20 +142,30 @@ public class JpaDistributionSetType extends AbstractJpaTypeEntity implements Dis
|
||||
.publishEvent(new DistributionSetTypeDeletedEvent(getTenant(), getId(), getClass()));
|
||||
}
|
||||
|
||||
private JpaDistributionSetType setModuleType(final SoftwareModuleType smType, final boolean mandatory) {
|
||||
private JpaDistributionSetType replaceOrAddModuleTypes(final Set<SoftwareModuleType> smTypes, final boolean mandatory, final boolean replace) {
|
||||
if (smTypes == null) {
|
||||
return this; // do not change
|
||||
}
|
||||
|
||||
if (elements.isEmpty()) {
|
||||
elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory));
|
||||
smTypes.forEach(smType -> elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory)));
|
||||
return this;
|
||||
}
|
||||
|
||||
// check if this was in the list before
|
||||
elements.stream()
|
||||
.filter(element -> element.getSmType().getKey().equals(smType.getKey()))
|
||||
.findAny()
|
||||
.ifPresentOrElse(
|
||||
element -> element.setMandatory(mandatory),
|
||||
() -> elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory)));
|
||||
smTypes.stream()
|
||||
.filter(smType -> !elements.contains(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory)))
|
||||
.collect(Collectors.toSet())
|
||||
.forEach(smType -> elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, mandatory)));
|
||||
|
||||
if (replace) {
|
||||
final Set<Long> smTypeIds = smTypes.stream()
|
||||
.map(SoftwareModuleType::getId)
|
||||
.collect(Collectors.toSet());
|
||||
elements.stream()
|
||||
.filter(element -> element.isMandatory() == mandatory && !smTypeIds.contains(element.getSmType().getId()))
|
||||
.collect(Collectors.toSet())
|
||||
.forEach(element -> elements.remove(element));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,6 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
|
||||
private boolean deleted;
|
||||
|
||||
@ToString.Exclude
|
||||
@Getter(AccessLevel.NONE)
|
||||
@ManyToMany(mappedBy = "modules", targetEntity = JpaDistributionSet.class, fetch = FetchType.LAZY)
|
||||
private List<DistributionSet> assignedTo;
|
||||
|
||||
@@ -174,29 +173,6 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
|
||||
locked = false;
|
||||
}
|
||||
|
||||
public void setDeleted(final boolean deleted) {
|
||||
if (assignedTo != null) {
|
||||
final List<DistributionSet> lockedDS = assignedTo.stream()
|
||||
.filter(DistributionSet::isLocked)
|
||||
.filter(ds -> !ds.isDeleted())
|
||||
.toList();
|
||||
if (!lockedDS.isEmpty()) {
|
||||
final StringBuilder sb = new StringBuilder("Part of ");
|
||||
if (lockedDS.size() == 1) {
|
||||
sb.append("a locked distribution set: ");
|
||||
} else {
|
||||
sb.append(lockedDS.size()).append(" locked distribution sets: ");
|
||||
}
|
||||
for (final DistributionSet ds : lockedDS) {
|
||||
sb.append(ds.getName()).append(":").append(ds.getVersion()).append(" (").append(ds.getId()).append("), ");
|
||||
}
|
||||
sb.delete(sb.length() - 2, sb.length());
|
||||
throw new LockedException(JpaSoftwareModule.class, getId(), "DELETE", sb.toString());
|
||||
}
|
||||
}
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCreateEvent() {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new SoftwareModuleCreatedEvent(this));
|
||||
|
||||
@@ -18,8 +18,8 @@ import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
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.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
@@ -37,7 +37,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
@Transactional(readOnly = true)
|
||||
public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity>
|
||||
public interface BaseEntityRepository<T extends AbstractJpaBaseEntity>
|
||||
extends PagingAndSortingRepository<T, Long>, CrudRepository<T, Long>, JpaSpecificationExecutor<T>,
|
||||
JpaSpecificationEntityGraphExecutor<T>, NoCountSliceRepository<T>, ACMRepository<T> {
|
||||
|
||||
@@ -118,11 +118,11 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
|
||||
}
|
||||
}
|
||||
|
||||
default <S extends AbstractJpaTenantAwareBaseEntity> Specification<S> byIdSpec(final Long id) {
|
||||
default <S extends AbstractJpaBaseEntity> Specification<S> byIdSpec(final Long id) {
|
||||
return (root, query, cb) -> cb.equal(root.get(AbstractJpaBaseEntity_.id), id);
|
||||
}
|
||||
|
||||
default <S extends AbstractJpaTenantAwareBaseEntity> Specification<S> byIdsSpec(final Iterable<Long> ids) {
|
||||
default <S extends AbstractJpaBaseEntity> Specification<S> byIdsSpec(final Iterable<Long> ids) {
|
||||
final Collection<Long> collection;
|
||||
if (ids instanceof Collection<Long> idCollection) {
|
||||
collection = idCollection;
|
||||
|
||||
@@ -25,7 +25,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
@@ -35,7 +35,7 @@ import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@Slf4j
|
||||
public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity> implements BaseEntityRepository<T> {
|
||||
public class BaseEntityRepositoryACM<T extends AbstractJpaBaseEntity> implements BaseEntityRepository<T> {
|
||||
|
||||
private static final String SPEC_MUST_NOT_BE_NULL = "Specification must not be null";
|
||||
private static final String APPENDED_ACCESS_RULES_SPEC_OF_NON_NULL_SPEC_MUST_NOT_BE_NULL =
|
||||
@@ -337,7 +337,7 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends AbstractJpaTenantAwareBaseEntity, R extends BaseEntityRepository<T>> R of(
|
||||
static <T extends AbstractJpaBaseEntity, R extends BaseEntityRepository<T>> R of(
|
||||
final R repository, @NonNull final AccessController<T> accessController) {
|
||||
Objects.requireNonNull(repository);
|
||||
Objects.requireNonNull(accessController);
|
||||
|
||||
@@ -36,7 +36,7 @@ public interface DistributionSetTagRepository
|
||||
* @param tagName to filter on
|
||||
* @return the {@link DistributionSetTag} if found, otherwise null
|
||||
*/
|
||||
Optional<DistributionSetTag> findByNameEquals(String tagName);
|
||||
Optional<JpaDistributionSetTag> findByNameEquals(String tagName);
|
||||
|
||||
/**
|
||||
* Returns all instances of the type.
|
||||
|
||||
@@ -19,7 +19,6 @@ import jakarta.persistence.NoResultException;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.BaseRepositoryTypeProvider;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -175,16 +174,4 @@ public class HawkbitBaseRepository<T, ID extends Serializable> extends SimpleJpa
|
||||
final List<S> content = query.getResultList();
|
||||
return new PageImpl<>(content, pageable, content.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link BaseRepositoryTypeProvider} leveraging our
|
||||
* {@link HawkbitBaseRepository} for all current use cases
|
||||
*/
|
||||
public static class RepositoryTypeProvider implements BaseRepositoryTypeProvider {
|
||||
|
||||
@Override
|
||||
public Class<?> getBaseRepositoryType(final Class<?> repositoryType) {
|
||||
return HawkbitBaseRepository.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,13 +31,13 @@ public interface SoftwareModuleTypeRepository extends BaseEntityRepository<JpaSo
|
||||
* @param key to search for
|
||||
* @return all {@link SoftwareModuleType}s in the repository with given {@link SoftwareModuleType#getKey()}
|
||||
*/
|
||||
Optional<SoftwareModuleType> findByKey(String key);
|
||||
Optional<JpaSoftwareModuleType> findByKey(String key);
|
||||
|
||||
/**
|
||||
* @param name to search for
|
||||
* @return all {@link SoftwareModuleType}s in the repository with given {@link SoftwareModuleType#getName()}
|
||||
*/
|
||||
Optional<SoftwareModuleType> findByName(String name);
|
||||
Optional<JpaSoftwareModuleType> findByName(String name);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety reasons (this is a "delete everything" query
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement.Create;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -31,6 +32,9 @@ class DistributionSetCreatedEventTest extends AbstractRemoteEntityEventTest<Dist
|
||||
@Override
|
||||
protected DistributionSet createEntity() {
|
||||
return distributionSetManagement.create(
|
||||
entityFactory.distributionSet().create().name("incomplete").version("2").description("incomplete").type("os"));
|
||||
Create.builder()
|
||||
.type(distributionSetTypeManagement.findByKey("os").orElseThrow())
|
||||
.name("incomplete").version("2").description("incomplete")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement.Create;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -38,6 +39,6 @@ class DistributionSetTagEventTest extends AbstractRemoteEntityEventTest<Distribu
|
||||
|
||||
@Override
|
||||
protected DistributionSetTag createEntity() {
|
||||
return distributionSetTagManagement.create(entityFactory.tag().create().name("tag1"));
|
||||
return distributionSetTagManagement.create(Create.builder().name("tag1").build());
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement.Create;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -36,6 +37,9 @@ class DistributionSetUpdatedEventTest extends AbstractRemoteEntityEventTest<Dist
|
||||
@Override
|
||||
protected DistributionSet createEntity() {
|
||||
return distributionSetManagement.create(
|
||||
entityFactory.distributionSet().create().name("incomplete").version("2").description("incomplete").type("os"));
|
||||
Create.builder()
|
||||
.type(distributionSetTypeManagement.findByKey("os").orElseThrow())
|
||||
.name("incomplete").version("2").description("incomplete")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,10 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||
@@ -38,10 +40,16 @@ class RolloutEventTest extends AbstractRemoteEntityEventTest<Rollout> {
|
||||
protected Rollout createEntity() {
|
||||
testdataFactory.createTarget("12345");
|
||||
final SoftwareModule module = softwareModuleManagement.create(
|
||||
entityFactory.softwareModule().create().name("swm").version("2").description("desc").type("os"));
|
||||
SoftwareModuleManagement.Create.builder()
|
||||
.type(softwareModuleTypeManagement.findByKey("os").orElseThrow())
|
||||
.name("swm").version("2").description("desc")
|
||||
.build());
|
||||
final DistributionSet ds = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("complete").version("2").description("complete")
|
||||
.type("os").modules(Collections.singletonList(module.getId())));
|
||||
.create(DistributionSetManagement.Create.builder()
|
||||
.type(distributionSetTypeManagement.findByKey("os").orElseThrow())
|
||||
.name("complete").version("2").description("complete")
|
||||
.modules(Set.of(module))
|
||||
.build());
|
||||
|
||||
return rolloutManagement.create(
|
||||
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSetId(ds),
|
||||
|
||||
@@ -11,9 +11,11 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
@@ -79,12 +81,16 @@ class RolloutGroupEventTest extends AbstractRemoteEntityEventTest<RolloutGroup>
|
||||
protected RolloutGroup createEntity() {
|
||||
testdataFactory.createTarget(UUID.randomUUID().toString());
|
||||
final SoftwareModule module = softwareModuleManagement.create(
|
||||
entityFactory.softwareModule().create().name("swm").version("2").description("desc").type("os"));
|
||||
SoftwareModuleManagement.Create.builder()
|
||||
.type(softwareModuleTypeManagement.findByKey("os").orElseThrow())
|
||||
.name("swm").version("2").description("desc")
|
||||
.build());
|
||||
final DistributionSet ds = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create()
|
||||
.name("complete").version("2")
|
||||
.description("complete").type("os")
|
||||
.modules(List.of(module.getId())));
|
||||
.create(DistributionSetManagement.Create.builder()
|
||||
.type(distributionSetTypeManagement.findByKey("os").orElseThrow())
|
||||
.name("complete").version("2").description("complete")
|
||||
.modules(Set.of(module))
|
||||
.build());
|
||||
|
||||
final Rollout entity = rolloutManagement.create(
|
||||
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSetId(ds),
|
||||
|
||||
@@ -176,16 +176,14 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
targets.stream().map(Target::getControllerId).toList(), tag.getId());
|
||||
}
|
||||
|
||||
protected List<DistributionSet> assignTag(final Collection<DistributionSet> sets,
|
||||
protected List<? extends DistributionSet> assignTag(final Collection<? extends DistributionSet> sets,
|
||||
final DistributionSetTag tag) {
|
||||
return distributionSetManagement.assignTag(
|
||||
sets.stream().map(DistributionSet::getId).toList(), tag.getId());
|
||||
return distributionSetManagement.assignTag(sets.stream().map(DistributionSet::getId).toList(), tag.getId());
|
||||
}
|
||||
|
||||
protected List<DistributionSet> unassignTag(final Collection<DistributionSet> sets,
|
||||
final DistributionSetTag tag) {
|
||||
return distributionSetManagement.unassignTag(
|
||||
sets.stream().map(DistributionSet::getId).toList(), tag.getId());
|
||||
protected List<? extends DistributionSet> unassignTag(
|
||||
final Collection<DistributionSet> sets, final DistributionSetTag tag) {
|
||||
return distributionSetManagement.unassignTag(sets.stream().map(DistributionSet::getId).toList(), tag.getId());
|
||||
}
|
||||
|
||||
protected TargetTypeAssignmentResult initiateTypeAssignment(final Collection<Target> targets, final TargetType type) {
|
||||
@@ -278,7 +276,7 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
|
||||
/**
|
||||
* Asserts that the given callable succeeds.
|
||||
*
|
||||
* </p>
|
||||
* Note: This method will assume that EntityNotFoundException is OK, as security tests use dummy (non-existing) IDs.
|
||||
* It matters to either callable succeeds without any exception or at most EntityNotFoundException.
|
||||
* All other cases will be considered as an error.
|
||||
@@ -288,7 +286,7 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
private void assertPermissionWorks(final Callable<?> callable) {
|
||||
try {
|
||||
callable.call();
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
if (th instanceof EntityNotFoundException) {
|
||||
log.info("Expected (at most) EntityNotFoundException catch: {}", th.getMessage());
|
||||
} else {
|
||||
@@ -298,8 +296,7 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
}
|
||||
|
||||
protected void finishAction(final Action action) {
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Action.Status.FINISHED));
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Action.Status.FINISHED));
|
||||
}
|
||||
|
||||
protected Set<TargetTag> getTargetTags(final String controllerId) {
|
||||
@@ -313,4 +310,4 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
private JpaRollout refresh(final Rollout rollout) {
|
||||
return rolloutRepository.findById(rollout.getId()).get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,13 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
public abstract class AbstractRepositoryManagementSecurityTest<T, C, U> extends AbstractJpaIntegrationTest {
|
||||
public abstract class AbstractRepositoryManagementSecurityTest<T extends BaseEntity, C, U extends Identifiable<Long>> extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
* @return the repository management to test with
|
||||
@@ -127,5 +129,4 @@ public abstract class AbstractRepositoryManagementSecurityTest<T, C, U> extends
|
||||
void findByRsqlPermissionCheck() {
|
||||
assertPermissions(() -> getRepositoryManagement().findByRsql("(name==*)", Pageable.ofSize(1)), List.of(SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
@@ -184,8 +185,10 @@ class DistributionSetAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSet permitted = testdataFactory.createDistributionSet();
|
||||
final DistributionSet readOnly = testdataFactory.createDistributionSet();
|
||||
final DistributionSet hidden = testdataFactory.createDistributionSet();
|
||||
final Long dsTagId = distributionSetTagManagement.create(entityFactory.tag().create().name("dsTag")).getId();
|
||||
final Long dsTag2Id = distributionSetTagManagement.create(entityFactory.tag().create().name("dsTag2")).getId();
|
||||
final Long dsTagId = distributionSetTagManagement.create(
|
||||
DistributionSetTagManagement.Create.builder().name("dsTag").build()).getId();
|
||||
final Long dsTag2Id = distributionSetTagManagement.create(
|
||||
DistributionSetTagManagement.Create.builder().name("dsTag2").build()).getId();
|
||||
|
||||
// perform tag assignment before setting access rules
|
||||
distributionSetManagement.assignTag(Arrays.asList(permitted.getId(), readOnly.getId(), hidden.getId()), dsTagId);
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement.Create;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
@@ -251,8 +252,10 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||
void checkAutoAssignWithFailures() {
|
||||
|
||||
// incomplete distribution set that will be assigned
|
||||
final DistributionSet setF = distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||
.name("dsA").version("1").type(testdataFactory.findOrCreateDefaultTestDsType()));
|
||||
final DistributionSet setF = distributionSetManagement.create(Create.builder()
|
||||
.type(testdataFactory.findOrCreateDefaultTestDsType())
|
||||
.name("dsA").version("1")
|
||||
.build());
|
||||
final DistributionSet setA = testdataFactory.createDistributionSet("dsA");
|
||||
final DistributionSet setB = testdataFactory.createDistributionSet("dsB");
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.event.TenantAwareEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
|
||||
@@ -211,7 +212,7 @@ class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
|
||||
void softwareModuleUpdateEventIsPublished() throws InterruptedException {
|
||||
final SoftwareModule softwareModule = testdataFactory.createSoftwareModuleApp();
|
||||
softwareModuleManagement
|
||||
.update(entityFactory.softwareModule().update(softwareModule.getId()).description("New"));
|
||||
.update(SoftwareModuleManagement.Update.builder().id(softwareModule.getId()).description("New").build());
|
||||
|
||||
final SoftwareModuleUpdatedEvent softwareModuleUpdatedEvent = eventListener
|
||||
.waitForEvent(SoftwareModuleUpdatedEvent.class);
|
||||
@@ -267,5 +268,4 @@ class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -660,9 +660,9 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// create two artifacts with identical SHA1 hash
|
||||
final Artifact artifact = artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(random),
|
||||
ds.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize));
|
||||
findFirstModuleByType(ds, osType).orElseThrow().getId(), "file1", false, artifactSize));
|
||||
final Artifact artifact2 = artifactManagement.create(new ArtifactUpload(new ByteArrayInputStream(random),
|
||||
ds2.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize));
|
||||
findFirstModuleByType(ds2, osType).orElseThrow().getId(), "file1", false, artifactSize));
|
||||
assertThat(artifact.getSha1Hash()).isEqualTo(artifact2.getSha1Hash());
|
||||
|
||||
assertThat(
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.Set;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.im.authentication.SpRole;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
@@ -291,8 +292,8 @@ class DeploymentManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void cancelActionsForDistributionSetPermissionsCheck() {
|
||||
assertPermissions(() -> {
|
||||
deploymentManagement.cancelActionsForDistributionSet(DistributionSetInvalidation.CancelationType.FORCE,
|
||||
entityFactory.distributionSet().create().build());
|
||||
deploymentManagement.cancelActionsForDistributionSet(
|
||||
DistributionSetInvalidation.CancelationType.FORCE, new JpaDistributionSet());
|
||||
return null;
|
||||
}, List.of(SpPermission.UPDATE_TARGET));
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import lombok.Getter;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
|
||||
@@ -129,7 +131,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that management get access react as specified on calls for non existing entities by means
|
||||
* Verifies that management get access react as specified on calls for non existing entities by means
|
||||
* of Optional not present.
|
||||
*/
|
||||
@Test
|
||||
@@ -140,8 +142,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that management queries react as specified on calls for non existing entities
|
||||
* by means of throwing EntityNotFoundException.
|
||||
* Verifies that management queries react as specified on calls for non existing entities
|
||||
* by means of throwing EntityNotFoundException.
|
||||
*/
|
||||
@Test
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1) })
|
||||
@@ -298,7 +300,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
// not exists
|
||||
assignDS.add(100_000L);
|
||||
|
||||
final Long tagId = distributionSetTagManagement.create(entityFactory.tag().create().name("Tag1")).getId();
|
||||
final Long tagId = distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("Tag1").build()).getId();
|
||||
|
||||
assertThatExceptionOfType(EntityNotFoundException.class)
|
||||
.isThrownBy(() -> distributionSetManagement.assignTag(assignDS, tagId))
|
||||
@@ -321,7 +323,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
|
||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) })
|
||||
// implicit lock })
|
||||
// implicit lock
|
||||
void multiAssigmentHistoryOverMultiplePagesResultsInTwoActiveAction() {
|
||||
final DistributionSet cancelDs = testdataFactory.createDistributionSet("Canceled DS", "1.0", Collections.emptyList());
|
||||
final DistributionSet cancelDs2 = testdataFactory.createDistributionSet("Canceled DS", "1.2", Collections.emptyList());
|
||||
@@ -336,7 +338,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels multiple active actions on a target. Expected behaviour is that with two active
|
||||
* Cancels multiple active actions on a target. Expected behaviour is that with two active
|
||||
* After canceling the first one also the target goes back to IN_SYNC as no open action is left.
|
||||
*/
|
||||
@Test
|
||||
@@ -384,7 +386,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels multiple active actions on a target. Expected behaviour is that with two active
|
||||
* Cancels multiple active actions on a target. Expected behaviour is that with two active
|
||||
* also the target goes back to IN_SYNC as no open action is left.
|
||||
*/
|
||||
@Test
|
||||
@@ -497,7 +499,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple offline deployment of a distribution set to a list of targets. Verifies that offline assigment
|
||||
* Simple offline deployment of a distribution set to a list of targets. Verifies that offline assigment
|
||||
* is correctly executed for targets that do not have a running update already. Those are ignored.
|
||||
*/
|
||||
@Test
|
||||
@@ -848,9 +850,9 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
.contains("Assignment initiated by user 'bumlux'")
|
||||
.contains("""
|
||||
Assignment automatically confirmed by initiator 'not_bumlux'.\s
|
||||
|
||||
|
||||
Auto confirmation activated by system user: 'bumlux'\s
|
||||
|
||||
|
||||
Remark: my personal remark""");
|
||||
} else {
|
||||
// assignment never required confirmation, auto-confirmation will not be
|
||||
@@ -1141,8 +1143,12 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
|
||||
final SoftwareModule os = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
final DistributionSet incomplete = distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||
.name("incomplete").version("v1").type(standardDsType).modules(Collections.singletonList(ah.getId())));
|
||||
final DistributionSet incomplete = distributionSetManagement.create(
|
||||
DistributionSetManagement.Create.builder()
|
||||
.type(standardDsType)
|
||||
.name("incomplete").version("v1")
|
||||
.modules(Set.of(ah))
|
||||
.build());
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("expected IncompleteDistributionSetException")
|
||||
@@ -1156,7 +1162,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple deployments or distribution set to target assignment test. Expected behaviour is that a new deployment
|
||||
* Multiple deployments or distribution set to target assignment test. Expected behaviour is that a new deployment
|
||||
* overides unfinished old one which are canceled as part of the operation.
|
||||
*/
|
||||
@Test
|
||||
@@ -1222,7 +1228,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple deployments or distribution set to target assignment test including finished response
|
||||
* Multiple deployments or distribution set to target assignment test including finished response
|
||||
* IN_SYNC status and installed DS is set to the assigned DS entry.
|
||||
*/
|
||||
@Test
|
||||
@@ -1317,12 +1323,11 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
* or {@link Target#getInstalledDistributionSet()}
|
||||
*/
|
||||
/**
|
||||
* Deletes distribution set. Expected behaviour is that a soft delete is performed
|
||||
* Deletes distribution set. Expected behaviour is that a soft delete is performed
|
||||
* if the DS is assigned to a target and a hard delete if the DS is not in use at all.
|
||||
*/
|
||||
@Test
|
||||
void deleteDistributionSet() {
|
||||
|
||||
final PageRequest pageRequest = PageRequest.of(0, 100, Direction.ASC, "id");
|
||||
|
||||
final String undeployedTargetPrefix = "undep-T";
|
||||
@@ -1351,7 +1356,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
// verify that deleted attribute is used correctly
|
||||
List<DistributionSet> allFoundDS = distributionSetManagement.findByCompleted(true, PAGE).getContent();
|
||||
List<? extends DistributionSet> allFoundDS = distributionSetManagement.findByCompleted(true, PAGE).getContent();
|
||||
assertThat(allFoundDS).as("no ds should be founded").isEmpty();
|
||||
|
||||
assertThat(distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(Arrays
|
||||
@@ -1359,7 +1364,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
PAGE).getContent()).as("wrong size of founded ds").hasSize(noOfDistributionSets);
|
||||
|
||||
IntStream.range(0, deploymentResult.getDistributionSets().size()).forEach(i -> testdataFactory.sendUpdateActionStatusToTargets(
|
||||
deploymentResult.getDeployedTargets(), Status.FINISHED, Collections.singletonList("blabla alles gut")));
|
||||
deploymentResult.getDeployedTargets(), Status.FINISHED, Collections.singletonList("blabla alles gut")));
|
||||
|
||||
// try to delete again
|
||||
distributionSetManagement.delete(deploymentResult.getDistributionSetIDs());
|
||||
@@ -1391,7 +1396,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
deployedTargetPrefix, noOfDeployedTargets, noOfDistributionSets, "myTestDS");
|
||||
|
||||
IntStream.range(0, deploymentResult.getDistributionSets().size()).forEach(i -> testdataFactory.sendUpdateActionStatusToTargets(
|
||||
deploymentResult.getDeployedTargets(), Status.FINISHED, Collections.singletonList("blabla alles gut")));
|
||||
deploymentResult.getDeployedTargets(), Status.FINISHED, Collections.singletonList("blabla alles gut")));
|
||||
|
||||
assertThat(targetManagement.count()).as("size of targets is wrong").isNotZero();
|
||||
assertThat(actionStatusRepository.count()).as("size of action status is wrong").isNotZero();
|
||||
@@ -1479,7 +1484,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
* The test verifies that the DS itself is not changed because of an target assignment
|
||||
* which is a relationship but not a changed on the entity itself..
|
||||
* which is a relationship but not a changed on the entity itself..
|
||||
*/
|
||||
@Test
|
||||
void checkThatDsRevisionsIsNotChangedWithTargetAssignment() {
|
||||
|
||||
@@ -13,12 +13,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractRepositoryManagementSecurityTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetFilter;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
@@ -26,22 +26,22 @@ import org.junit.jupiter.api.Test;
|
||||
* Story: SecurityTests DistributionSetManagement
|
||||
*/
|
||||
class DistributionSetManagementSecurityTest
|
||||
extends AbstractRepositoryManagementSecurityTest<DistributionSet, DistributionSetCreate, DistributionSetUpdate> {
|
||||
extends AbstractRepositoryManagementSecurityTest<DistributionSet, DistributionSetManagement.Create, DistributionSetManagement.Update> {
|
||||
|
||||
@Override
|
||||
protected RepositoryManagement<DistributionSet, DistributionSetCreate, DistributionSetUpdate> getRepositoryManagement() {
|
||||
protected DistributionSetManagement getRepositoryManagement() {
|
||||
return distributionSetManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DistributionSetCreate getCreateObject() {
|
||||
return entityFactory.distributionSet().create().name("name").version("1.0.0").type("type");
|
||||
protected DistributionSetManagement.Create getCreateObject() {
|
||||
return DistributionSetManagement.Create.builder().name("name").version("1.0.0").type(defaultDsType()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DistributionSetUpdate getUpdateObject() {
|
||||
return entityFactory.distributionSet().update(0L).name("a new name")
|
||||
.description("a new description").version("a new version").requiredMigrationStep(true);
|
||||
protected DistributionSetManagement.Update getUpdateObject() {
|
||||
return DistributionSetManagement.Update.builder().id(0L).name("a new name")
|
||||
.description("a new description").version("a new version").requiredMigrationStep(true).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,7 +87,7 @@ class DistributionSetManagementSecurityTest
|
||||
* Tests ManagementAPI PreAuthorized method with correct and insufficient permissions.
|
||||
*/
|
||||
@Test
|
||||
void getMetadataPermissiosCheck() {
|
||||
void getMetadataPermissionsCheck() {
|
||||
assertPermissions(() -> distributionSetManagement.getMetadata(1L), List.of(SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class DistributionSetManagementSecurityTest
|
||||
@Test
|
||||
void updateMetadataPermissionsCheck() {
|
||||
assertPermissions(() -> {
|
||||
distributionSetManagement.updateMetadata(1L,"key", "value");
|
||||
distributionSetManagement.updateMetadata(1L, "key", "value");
|
||||
return null;
|
||||
},
|
||||
List.of(SpPermission.UPDATE_REPOSITORY));
|
||||
@@ -287,9 +287,12 @@ class DistributionSetManagementSecurityTest
|
||||
*/
|
||||
@Test
|
||||
void invalidatePermissionsCheck() {
|
||||
distributionSetTypeManagement.create(entityFactory.distributionSetType().create().key("type").name("name"));
|
||||
final DistributionSetType dsType = distributionSetTypeManagement.create(DistributionSetTypeManagement.Create.builder()
|
||||
.key("type").name("name").build());
|
||||
final DistributionSet ds = distributionSetManagement.create(DistributionSetManagement.Create.builder()
|
||||
.type(dsType).name("test").version("1.0.0").build());
|
||||
assertPermissions(() -> {
|
||||
distributionSetManagement.invalidate(entityFactory.distributionSet().create().name("name").version("1.0").type("type").build());
|
||||
((DistributionSetManagement) distributionSetManagement).invalidate(ds);
|
||||
return null;
|
||||
}, List.of(SpPermission.UPDATE_REPOSITORY, SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -30,9 +31,10 @@ import jakarta.validation.ConstraintViolationException;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
||||
@@ -96,7 +98,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that management queries react as specified on calls for non existing entities by means of
|
||||
* Verifies that management queries react as specified on calls for non existing entities by means of
|
||||
* throwing EntityNotFoundException.
|
||||
*/
|
||||
@Test
|
||||
@@ -133,9 +135,6 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.unassignTag(singletonList(NOT_EXIST_IDL), dsTag.getId()), "DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.create(
|
||||
entityFactory.distributionSet().create().name("xxx").type(NOT_EXIST_ID)), "DistributionSetType");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.createMetadata(NOT_EXIST_IDL, Map.of("123", "123")), "DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.delete(singletonList(NOT_EXIST_IDL)), "DistributionSet");
|
||||
@@ -154,10 +153,11 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
.hasMessageContaining("DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> distributionSetManagement.update(entityFactory.distributionSet().update(NOT_EXIST_IDL)), "DistributionSet");
|
||||
() -> distributionSetManagement.update(DistributionSetManagement.Update.builder().id(NOT_EXIST_IDL).build()),
|
||||
"DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.updateMetadata(NOT_EXIST_IDL,"xxx", "xxx"), "DistributionSet");
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.updateMetadata(set.getId(),NOT_EXIST_ID, "xxx"), "DistributionSet");
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.updateMetadata(NOT_EXIST_IDL, "xxx", "xxx"), "DistributionSet");
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.updateMetadata(set.getId(), NOT_EXIST_ID, "xxx"), "DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.getOrElseThrowException(NOT_EXIST_IDL), "DistributionSet");
|
||||
|
||||
@@ -199,7 +199,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void createDistributionSetWithImplicitType() {
|
||||
final DistributionSet set = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("newtypesoft").version("1"));
|
||||
.create(DistributionSetManagement.Create.builder().type(defaultDsType()).name("newtypesoft").version("1").build());
|
||||
|
||||
assertThat(set.getType())
|
||||
.as("Type should be equal to default type of tenant")
|
||||
@@ -212,7 +212,8 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createDistributionSetWithDuplicateNameAndVersionFails() {
|
||||
final DistributionSetCreate distributionSetCreate = entityFactory.distributionSet().create().name("newtypesoft").version("1");
|
||||
final DistributionSetManagement.Create distributionSetCreate =
|
||||
DistributionSetManagement.Create.builder().type(defaultDsType()).name("newtypesoft").version("1").build();
|
||||
distributionSetManagement.create(distributionSetCreate);
|
||||
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class).isThrownBy(() -> distributionSetManagement.create(distributionSetCreate));
|
||||
@@ -223,14 +224,14 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createMultipleDistributionSetsWithImplicitType() {
|
||||
final List<DistributionSetCreate> creates = new ArrayList<>(10);
|
||||
final List<DistributionSetManagement.Create> creates = new ArrayList<>(10);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
creates.add(entityFactory.distributionSet().create().name("newtypesoft" + i).version("1" + i));
|
||||
creates.add(DistributionSetManagement.Create.builder().type(defaultDsType()).name("newtypesoft" + i).version("1" + i).build());
|
||||
}
|
||||
|
||||
assertThat(distributionSetManagement.create(creates))
|
||||
.as("Type should be equal to default type of tenant")
|
||||
.are(new Condition<>() {
|
||||
.are(new Condition<DistributionSet>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(final DistributionSet value) {
|
||||
@@ -308,9 +309,10 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assignDS.add(testdataFactory.createDistributionSet("DS" + i, "1.0", Collections.emptyList()).getId());
|
||||
}
|
||||
|
||||
final DistributionSetTag tag = distributionSetTagManagement.create(entityFactory.tag().create().name(TAG1_NAME));
|
||||
final DistributionSetTag tag = distributionSetTagManagement.create(
|
||||
DistributionSetTagManagement.Create.builder().name(TAG1_NAME).build());
|
||||
|
||||
final List<DistributionSet> assignedDS = distributionSetManagement.assignTag(assignDS, tag.getId());
|
||||
final List<? extends DistributionSet> assignedDS = distributionSetManagement.assignTag(assignDS, tag.getId());
|
||||
assertThat(assignedDS).as("assigned ds has wrong size").hasSize(4);
|
||||
assignedDS.stream().map(JpaDistributionSet.class::cast).forEach(ds -> assertThat(ds.getTags())
|
||||
.as("ds has wrong tag size")
|
||||
@@ -362,7 +364,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
.isInstanceOf(EntityReadOnlyException.class);
|
||||
|
||||
// not allowed as it is assigned now
|
||||
final Long appId = getOrThrow(ds.findFirstModuleByType(appType)).getId();
|
||||
final Long appId = getOrThrow(findFirstModuleByType(ds, appType)).getId();
|
||||
assertThatThrownBy(() -> distributionSetManagement.unassignSoftwareModule(dsId, appId))
|
||||
.isInstanceOf(EntityReadOnlyException.class);
|
||||
}
|
||||
@@ -373,17 +375,22 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void updateDistributionSetUnsupportedModuleFails() {
|
||||
final Long setId = distributionSetManagement.create(
|
||||
entityFactory.distributionSet().create()
|
||||
DistributionSetManagement.Create.builder()
|
||||
.type(distributionSetTypeManagement.create(
|
||||
entityFactory.distributionSetType().create()
|
||||
DistributionSetTypeManagement.Create.builder()
|
||||
.key("test")
|
||||
.name("test")
|
||||
.mandatory(singletonList(osType.getId()))).getKey())
|
||||
.mandatoryModuleTypes(Set.of(osType))
|
||||
.build()))
|
||||
.name("agent-hub2")
|
||||
.version("1.0.5")).getId();
|
||||
.version("1.0.5")
|
||||
.build()).getId();
|
||||
|
||||
final Set<Long> moduleId = Set.of(softwareModuleManagement.create(
|
||||
entityFactory.softwareModule().create().name("agent-hub2").version("1.0.5").type(appType.getKey())).getId());
|
||||
SoftwareModuleManagement.Create.builder()
|
||||
.type(appType)
|
||||
.name("agent-hub2").version("1.0.5")
|
||||
.build()).getId());
|
||||
|
||||
// update data
|
||||
assertThatThrownBy(() -> distributionSetManagement.assignSoftwareModules(setId, moduleId))
|
||||
@@ -403,17 +410,17 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
// legal update of module addition
|
||||
distributionSetManagement.assignSoftwareModules(ds.getId(), Set.of(os.getId()));
|
||||
ds = getOrThrow(distributionSetManagement.getWithDetails(ds.getId()));
|
||||
assertThat(getOrThrow(ds.findFirstModuleByType(osType))).isEqualTo(os);
|
||||
assertThat(getOrThrow(findFirstModuleByType(ds, osType))).isEqualTo(os);
|
||||
|
||||
// legal update of module removal
|
||||
distributionSetManagement.unassignSoftwareModule(ds.getId(),
|
||||
getOrThrow(ds.findFirstModuleByType(appType)).getId());
|
||||
getOrThrow(findFirstModuleByType(ds, appType)).getId());
|
||||
ds = getOrThrow(distributionSetManagement.getWithDetails(ds.getId()));
|
||||
assertThat(ds.findFirstModuleByType(appType)).isNotPresent();
|
||||
assertThat(findFirstModuleByType(ds, appType)).isNotPresent();
|
||||
|
||||
// Update description
|
||||
distributionSetManagement.update(entityFactory.distributionSet().update(ds.getId()).name("a new name")
|
||||
.description("a new description").version("a new version").requiredMigrationStep(true));
|
||||
distributionSetManagement.update(DistributionSetManagement.Update.builder().id(ds.getId()).name("a new name")
|
||||
.description("a new description").version("a new version").requiredMigrationStep(true).build());
|
||||
ds = getOrThrow(distributionSetManagement.getWithDetails(ds.getId()));
|
||||
assertThat(ds.getDescription()).isEqualTo("a new description");
|
||||
assertThat(ds.getName()).isEqualTo("a new name");
|
||||
@@ -428,7 +435,8 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
void updateInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
final DistributionSetUpdate update = entityFactory.distributionSet().update(distributionSet.getId()).name("new_name");
|
||||
final DistributionSetManagement.Update update =
|
||||
DistributionSetManagement.Update.builder().id(distributionSet.getId()).name("new_name").build();
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception").isThrownBy(() -> distributionSetManagement.update(update));
|
||||
}
|
||||
@@ -548,22 +556,23 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void searchDistributionSetsOnFilters() {
|
||||
DistributionSetTag dsTagA = distributionSetTagManagement
|
||||
.create(entityFactory.tag().create().name("DistributionSetTag-A"));
|
||||
.create(DistributionSetTagManagement.Create.builder().name("DistributionSetTag-A").build());
|
||||
final DistributionSetTag dsTagB = distributionSetTagManagement
|
||||
.create(entityFactory.tag().create().name("DistributionSetTag-B"));
|
||||
.create(DistributionSetTagManagement.Create.builder().name("DistributionSetTag-B").build());
|
||||
final DistributionSetTag dsTagC = distributionSetTagManagement
|
||||
.create(entityFactory.tag().create().name("DistributionSetTag-C"));
|
||||
distributionSetTagManagement.create(entityFactory.tag().create().name("DistributionSetTag-D"));
|
||||
.create(DistributionSetTagManagement.Create.builder().name("DistributionSetTag-C").build());
|
||||
distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("DistributionSetTag-D").build());
|
||||
|
||||
List<DistributionSet> dsGroup1 = testdataFactory.createDistributionSets("", 5);
|
||||
List<? extends DistributionSet> dsGroup1 = testdataFactory.createDistributionSets("", 5);
|
||||
final String dsGroup2Prefix = "test";
|
||||
List<DistributionSet> dsGroup2 = testdataFactory.createDistributionSets(dsGroup2Prefix, 5);
|
||||
List<? extends DistributionSet> dsGroup2 = testdataFactory.createDistributionSets(dsGroup2Prefix, 5);
|
||||
DistributionSet dsDeleted = testdataFactory.createDistributionSet("testDeleted");
|
||||
final DistributionSet dsInComplete = distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||
.name("notcomplete").version("1").type(standardDsType.getKey()));
|
||||
final DistributionSet dsInComplete = distributionSetManagement.create(
|
||||
DistributionSetManagement.Create.builder()
|
||||
.name("notcomplete").version("1").type(standardDsType).build());
|
||||
|
||||
DistributionSetType newType = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("foo").name("bar").description("test"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("foo").name("bar").description("test").build());
|
||||
|
||||
distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(newType.getId(),
|
||||
singletonList(osType.getId()));
|
||||
@@ -571,8 +580,11 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
Arrays.asList(appType.getId(), runtimeType.getId()));
|
||||
|
||||
final DistributionSet dsNewType = distributionSetManagement.create(
|
||||
entityFactory.distributionSet().create().name("newtype").version("1").type(newType.getKey()).modules(
|
||||
dsDeleted.getModules().stream().map(SoftwareModule::getId).toList()));
|
||||
DistributionSetManagement.Create.builder()
|
||||
.type(newType)
|
||||
.name("newtype").version("1")
|
||||
.modules(new HashSet<>(dsDeleted.getModules()))
|
||||
.build());
|
||||
|
||||
assignDistributionSet(dsDeleted, testdataFactory.createTargets(5));
|
||||
distributionSetManagement.delete(dsDeleted.getId());
|
||||
@@ -585,10 +597,10 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
dsGroup2 = assignTag(dsGroup2, dsTagA);
|
||||
dsTagA = getOrThrow(distributionSetTagRepository.findByNameEquals(dsTagA.getName()));
|
||||
|
||||
final List<DistributionSet> allDistributionSets = Stream
|
||||
final List<? extends DistributionSet> allDistributionSets = Stream
|
||||
.of(dsGroup1, dsGroup2, Arrays.asList(dsDeleted, dsInComplete, dsNewType)).flatMap(Collection::stream)
|
||||
.toList();
|
||||
final List<DistributionSet> dsGroup1WithGroup2 = Stream.of(dsGroup1, dsGroup2).flatMap(Collection::stream)
|
||||
final List<? extends DistributionSet> dsGroup1WithGroup2 = Stream.of(dsGroup1, dsGroup2).flatMap(Collection::stream)
|
||||
.toList();
|
||||
final int sizeOfAllDistributionSets = allDistributionSets.size();
|
||||
|
||||
@@ -604,8 +616,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
validateDeletedAndCompleted(dsGroup1WithGroup2, dsNewType, dsDeleted);
|
||||
validateDeletedAndCompletedAndType(dsGroup1WithGroup2, dsDeleted, newType, dsNewType);
|
||||
validateDeletedAndCompletedAndTypeAndSearchText(dsGroup2, newType, dsGroup2Prefix);
|
||||
validateDeletedAndCompletedAndTypeAndSearchText(dsGroup1WithGroup2, dsDeleted, dsInComplete, dsNewType, newType,
|
||||
":1");
|
||||
validateDeletedAndCompletedAndTypeAndSearchText(dsGroup1WithGroup2, dsDeleted, dsInComplete, dsNewType, newType, ":1");
|
||||
validateDeletedAndCompletedAndTypeAndSearchTextAndTag(dsGroup2, dsTagA, dsGroup2Prefix);
|
||||
}
|
||||
|
||||
@@ -729,21 +740,22 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
/**
|
||||
* Test implicit locks for a DS and skip tags.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
void isImplicitLockApplicableForDistributionSet() {
|
||||
final JpaDistributionSetManagement distributionSetManagement = (JpaDistributionSetManagement) this.distributionSetManagement;
|
||||
final JpaDistributionSetManagement distributionSetManagement = (JpaDistributionSetManagement) (DistributionSetManagement) this.distributionSetManagement;
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds-non-skip");
|
||||
// assert that implicit lock is applicable for non skip tags
|
||||
assertThat(distributionSetManagement.isImplicitLockApplicable(distributionSet)).isTrue();
|
||||
|
||||
assertThat(repositoryProperties.getSkipImplicitLockForTags().size()).isNotZero();
|
||||
final List<DistributionSetTag> skipTags = distributionSetTagManagement.create(
|
||||
final List<? extends DistributionSetTag> skipTags = distributionSetTagManagement.create(
|
||||
repositoryProperties.getSkipImplicitLockForTags().stream()
|
||||
.map(String::toLowerCase)
|
||||
// remove same in case-insensitive terms tags
|
||||
// in of case-insensitive db's it will end up as same names and constraint violation (?)
|
||||
.distinct()
|
||||
.map(skipTag -> entityFactory.tag().create().name(skipTag))
|
||||
.map(skipTag -> (DistributionSetTagManagement.Create)DistributionSetTagManagement.Create.builder().name(skipTag).build())
|
||||
.toList());
|
||||
// assert that implicit lock locks for every skip tag
|
||||
skipTags.forEach(skipTag -> {
|
||||
@@ -829,7 +841,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a DS that is in use by either target assignment or rollout. Expected behaviour is a soft delete on the database, i.e. only marked as
|
||||
* Deletes a DS that is in use by either target assignment or rollout. Expected behaviour is a soft delete on the database, i.e. only marked as
|
||||
* deleted, kept as reference but unavailable for future use..
|
||||
*/
|
||||
@Test
|
||||
@@ -874,7 +886,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
testdataFactory.createDistributionSet("test" + i);
|
||||
}
|
||||
|
||||
final List<DistributionSet> foundDs = distributionSetManagement.get(searchIds);
|
||||
final List<? extends DistributionSet> foundDs = distributionSetManagement.get(searchIds);
|
||||
|
||||
assertThat(foundDs).hasSize(3);
|
||||
|
||||
@@ -1006,91 +1018,92 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void createAndUpdateDistributionSetWithInvalidDescription(final DistributionSet set) {
|
||||
final DistributionSetCreate distributionSetCreate =
|
||||
entityFactory.distributionSet().create().name("a").version("a").description(randomString(513));
|
||||
final DistributionSetManagement.Create distributionSetCreate =
|
||||
DistributionSetManagement.Create.builder().name("a").version("a").description(randomString(513)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too long description should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate2 =
|
||||
entityFactory.distributionSet().create().name("a").version("a").description(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Create distributionSetCreate2 =
|
||||
DistributionSetManagement.Create.builder().name("a").version("a").description(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with invalid description should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate2));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate =
|
||||
entityFactory.distributionSet().update(set.getId()).description(randomString(513));
|
||||
final DistributionSetManagement.Update distributionSetUpdate =
|
||||
DistributionSetManagement.Update.builder().id(set.getId()).description(randomString(513)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too long description should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate2 = entityFactory.distributionSet().update(set.getId()).description(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Update distributionSetUpdate2 =
|
||||
DistributionSetManagement.Update.builder().id(set.getId()).description(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with invalid characters should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate2));
|
||||
}
|
||||
|
||||
private void createAndUpdateDistributionSetWithInvalidName(final DistributionSet set) {
|
||||
final DistributionSetCreate distributionSetCreate = entityFactory.distributionSet().create()
|
||||
.version("a").name(randomString(NamedEntity.NAME_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Create distributionSetCreate = DistributionSetManagement.Create.builder()
|
||||
.version("a").name(randomString(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too long name should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate2 = entityFactory.distributionSet().create().version("a").name("");
|
||||
final DistributionSetManagement.Create distributionSetCreate2 = DistributionSetManagement.Create.builder().version("a").name("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too short name should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate2));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate3 = entityFactory.distributionSet().create().version("a").name(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Create distributionSetCreate3 = DistributionSetManagement.Create.builder().version("a").name(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with invalid characters in name should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate3));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate = entityFactory.distributionSet().update(set.getId())
|
||||
.name(randomString(NamedEntity.NAME_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Update distributionSetUpdate = DistributionSetManagement.Update.builder().id(set.getId())
|
||||
.name(randomString(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too long name should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate2 = entityFactory.distributionSet().update(set.getId()).name(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Update distributionSetUpdate2 = DistributionSetManagement.Update.builder().id(set.getId()).name(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with invalid characters should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate2));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate3 = entityFactory.distributionSet().update(set.getId()).name("");
|
||||
final DistributionSetManagement.Update distributionSetUpdate3 = DistributionSetManagement.Update.builder().id(set.getId()).name("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too short name should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate3));
|
||||
}
|
||||
|
||||
private void createAndUpdateDistributionSetWithInvalidVersion(final DistributionSet set) {
|
||||
final DistributionSetCreate distributionSetCreate = entityFactory.distributionSet().create()
|
||||
.name("a").version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Create distributionSetCreate = DistributionSetManagement.Create.builder()
|
||||
.name("a").version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too long version should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate2 = entityFactory.distributionSet().create().name("a").version("");
|
||||
final DistributionSetManagement.Create distributionSetCreate2 = DistributionSetManagement.Create.builder().name("a").version("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too short version should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate2));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate = entityFactory.distributionSet().update(set.getId())
|
||||
.version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Update distributionSetUpdate = DistributionSetManagement.Update.builder().id(set.getId())
|
||||
.version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too long version should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate2 = entityFactory.distributionSet().update(set.getId()).version("");
|
||||
final DistributionSetManagement.Update distributionSetUpdate2 = DistributionSetManagement.Update.builder().id(set.getId()).version("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("entity with too short version should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate2));
|
||||
}
|
||||
|
||||
private void validateFindAll(final List<DistributionSet> expectedDistributionsets) {
|
||||
private void validateFindAll(final List<? extends DistributionSet> expectedDistributionSets) {
|
||||
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder(), expectedDistributionsets);
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder(), expectedDistributionSets);
|
||||
}
|
||||
|
||||
private void validateDeleted(final DistributionSet deletedDistributionSet, final int notDeletedSize) {
|
||||
@@ -1119,51 +1132,44 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
DistributionSetFilter.builder().typeId(standardDsType.getId()), standardDsTypeSize, dsNewType);
|
||||
}
|
||||
|
||||
private void validateSearchText(final List<DistributionSet> allDistributionSets, final String dsNamePrefix) {
|
||||
|
||||
final List<DistributionSet> withTestNamePrefix = allDistributionSets.stream()
|
||||
private void validateSearchText(final List<? extends DistributionSet> allDistributionSets, final String dsNamePrefix) {
|
||||
final List<? extends DistributionSet> withTestNamePrefix = allDistributionSets.stream()
|
||||
.filter(ds -> ds.getName().startsWith(dsNamePrefix)).toList();
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(dsNamePrefix),
|
||||
withTestNamePrefix);
|
||||
|
||||
final List<DistributionSet> withTestNameExact = withTestNamePrefix.stream()
|
||||
final List<? extends DistributionSet> withTestNameExact = withTestNamePrefix.stream()
|
||||
.filter(ds -> ds.getName().equals(dsNamePrefix)).toList();
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(
|
||||
DistributionSetFilter.builder().searchText(dsNamePrefix + ":"), withTestNameExact);
|
||||
|
||||
final List<DistributionSet> withTestNameExactAndVersionPrefix = withTestNameExact.stream()
|
||||
final List<? extends DistributionSet> withTestNameExactAndVersionPrefix = withTestNameExact.stream()
|
||||
.filter(ds -> ds.getVersion().startsWith("1")).toList();
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(
|
||||
DistributionSetFilter.builder().searchText(dsNamePrefix + ":1"),
|
||||
withTestNameExactAndVersionPrefix);
|
||||
|
||||
final List<DistributionSet> dsWithExactNameAndVersion = withTestNameExactAndVersionPrefix.stream()
|
||||
final List<? extends DistributionSet> dsWithExactNameAndVersion = withTestNameExactAndVersionPrefix.stream()
|
||||
.filter(ds -> ds.getVersion().equals("1.0.0")).toList();
|
||||
assertThat(dsWithExactNameAndVersion).hasSize(1);
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(
|
||||
DistributionSetFilter.builder().searchText(dsNamePrefix + ":1.0.0"), dsWithExactNameAndVersion);
|
||||
|
||||
final List<DistributionSet> withVersionPrefix = allDistributionSets.stream()
|
||||
final List<? extends DistributionSet> withVersionPrefix = allDistributionSets.stream()
|
||||
.filter(ds -> ds.getVersion().startsWith("1.0.")).toList();
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":1.0."),
|
||||
withVersionPrefix);
|
||||
|
||||
final List<DistributionSet> withVersionExact = withVersionPrefix.stream()
|
||||
final List<? extends DistributionSet> withVersionExact = withVersionPrefix.stream()
|
||||
.filter(ds -> ds.getVersion().equals("1.0.0")).toList();
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":1.0.0"),
|
||||
withVersionExact);
|
||||
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":"),
|
||||
allDistributionSets);
|
||||
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(" : "),
|
||||
allDistributionSets);
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":1.0.0"), withVersionExact);
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":"), allDistributionSets);
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(" : "), allDistributionSets);
|
||||
}
|
||||
|
||||
private void validateTags(final DistributionSetTag dsTagA, final DistributionSetTag dsTagB,
|
||||
final DistributionSetTag dsTagC, final List<DistributionSet> dsWithTagA,
|
||||
final List<DistributionSet> dsWithTagB) {
|
||||
|
||||
final DistributionSetTag dsTagC, final List<? extends DistributionSet> dsWithTagA,
|
||||
final List<? extends DistributionSet> dsWithTagB) {
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(
|
||||
DistributionSetFilter.builder().tagNames(singletonList(dsTagA.getName())), dsWithTagA);
|
||||
|
||||
@@ -1182,7 +1188,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
DistributionSetFilter.builder().tagNames(singletonList(dsTagC.getName())));
|
||||
}
|
||||
|
||||
private void validateDeletedAndCompleted(final List<DistributionSet> completedStandardType,
|
||||
private void validateDeletedAndCompleted(final List<? extends DistributionSet> completedStandardType,
|
||||
final DistributionSet dsNewType, final DistributionSet dsDeleted) {
|
||||
|
||||
final List<DistributionSet> completedNotDeleted = new ArrayList<>(completedStandardType);
|
||||
@@ -1199,7 +1205,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
DistributionSetFilter.builder().isComplete(Boolean.FALSE).isDeleted(Boolean.TRUE));
|
||||
}
|
||||
|
||||
private void validateDeletedAndCompletedAndType(final List<DistributionSet> deletedAndCompletedAndStandardType,
|
||||
private void validateDeletedAndCompletedAndType(final List<? extends DistributionSet> deletedAndCompletedAndStandardType,
|
||||
final DistributionSet dsDeleted, final DistributionSetType newType, final DistributionSet dsNewType) {
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.FALSE)
|
||||
.isComplete(Boolean.TRUE).typeId(standardDsType.getId()), deletedAndCompletedAndStandardType);
|
||||
@@ -1213,9 +1219,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void validateDeletedAndCompletedAndTypeAndSearchText(
|
||||
final List<DistributionSet> completedAndStandardTypeAndSearchText, final DistributionSetType newType,
|
||||
final String text) {
|
||||
|
||||
final List<? extends DistributionSet> completedAndStandardTypeAndSearchText, final DistributionSetType newType, final String text) {
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.FALSE)
|
||||
.isComplete(Boolean.TRUE).typeId(standardDsType.getId()).searchText(text),
|
||||
completedAndStandardTypeAndSearchText);
|
||||
@@ -1232,7 +1236,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void validateDeletedAndCompletedAndTypeAndSearchText(
|
||||
final List<DistributionSet> completedAndNotDeletedStandardTypeAndFilterString,
|
||||
final List<? extends DistributionSet> completedAndNotDeletedStandardTypeAndFilterString,
|
||||
final DistributionSet dsDeleted, final DistributionSet dsInComplete, final DistributionSet dsNewType,
|
||||
final DistributionSetType newType, final String filterString) {
|
||||
|
||||
@@ -1263,9 +1267,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void validateDeletedAndCompletedAndTypeAndSearchTextAndTag(
|
||||
final List<DistributionSet> completedAndStandartTypeAndSearchTextAndTagA, final DistributionSetTag dsTagA,
|
||||
final String text) {
|
||||
|
||||
final List<? extends DistributionSet> completedAndStandartTypeAndSearchTextAndTagA, final DistributionSetTag dsTagA, final String text) {
|
||||
assertThatFilterContainsOnlyGivenDistributionSets(
|
||||
DistributionSetFilter.builder().isComplete(Boolean.TRUE).typeId(standardDsType.getId())
|
||||
.searchText(text).tagNames(singletonList(dsTagA.getName())),
|
||||
@@ -1282,9 +1284,9 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void assertThatFilterContainsOnlyGivenDistributionSets(final DistributionSetFilterBuilder filterBuilder,
|
||||
final List<DistributionSet> distributionSets) {
|
||||
final List<? extends DistributionSet> distributionSets) {
|
||||
final int expectedDsSize = distributionSets.size();
|
||||
assertThat(distributionSetManagement.findByDistributionSetFilter(filterBuilder.build(), PAGE).getContent())
|
||||
assertThat(((DistributionSetManagement)distributionSetManagement).findByDistributionSetFilter(filterBuilder.build(), PAGE).getContent())
|
||||
.hasSize(expectedDsSize).containsOnly(distributionSets.toArray(new DistributionSet[expectedDsSize]));
|
||||
}
|
||||
|
||||
@@ -1295,7 +1297,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private void assertThatFilterHasSizeAndDoesNotContainDistributionSet(
|
||||
final DistributionSetFilterBuilder filterBuilder, final int size, final DistributionSet ds) {
|
||||
assertThat(distributionSetManagement.findByDistributionSetFilter(filterBuilder.build(), PAGE).getContent())
|
||||
assertThat(((DistributionSetManagement)distributionSetManagement).findByDistributionSetFilter(filterBuilder.build(), PAGE).getContent())
|
||||
.hasSize(size).doesNotContain(ds);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,8 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagUpdate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractRepositoryManagementSecurityTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -25,21 +24,22 @@ import org.springframework.data.domain.Pageable;
|
||||
* Feature: SecurityTests - DistributionSetTagManagement<br/>
|
||||
* Story: SecurityTests DistributionSetTagManagement
|
||||
*/
|
||||
class DistributionSetTagManagementSecurityTest extends AbstractRepositoryManagementSecurityTest<DistributionSetTag, TagCreate, TagUpdate> {
|
||||
class DistributionSetTagManagementSecurityTest
|
||||
extends AbstractRepositoryManagementSecurityTest<DistributionSetTag, DistributionSetTagManagement.Create, DistributionSetTagManagement.Update> {
|
||||
|
||||
@Override
|
||||
protected RepositoryManagement<DistributionSetTag, TagCreate, TagUpdate> getRepositoryManagement() {
|
||||
protected RepositoryManagement getRepositoryManagement() {
|
||||
return distributionSetTagManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TagCreate getCreateObject() {
|
||||
return entityFactory.tag().create().name(String.format("tag-%d", new Random().nextInt()));
|
||||
protected DistributionSetTagManagement.Create getCreateObject() {
|
||||
return DistributionSetTagManagement.Create.builder().name(String.format("tag-%d", new Random().nextInt())).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TagUpdate getUpdateObject() {
|
||||
return entityFactory.tag().update(1L).name("tag");
|
||||
protected DistributionSetTagManagement.Update getUpdateObject() {
|
||||
return DistributionSetTagManagement.Update.builder().id(1L).name("tag").build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,8 +22,6 @@ import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagUpdate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
|
||||
@@ -60,7 +58,7 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that management queries react as specified on calls for non existing entities by means of throwing
|
||||
* Verifies that management queries react as specified on calls for non existing entities by means of throwing
|
||||
* EntityNotFoundException.
|
||||
*/
|
||||
@Test
|
||||
@@ -69,10 +67,9 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Expect(type = TargetTagUpdatedEvent.class, count = 0) })
|
||||
void entityQueriesReferringToNotExistingEntitiesThrowsException() {
|
||||
verifyThrownExceptionBy(() -> distributionSetTagManagement.delete(NOT_EXIST_ID), "DistributionSetTag");
|
||||
verifyThrownExceptionBy(() -> distributionSetTagManagement.findByDistributionSet(NOT_EXIST_IDL, PAGE),
|
||||
"DistributionSet");
|
||||
verifyThrownExceptionBy(() -> distributionSetTagManagement.update(entityFactory.tag().update(NOT_EXIST_IDL)),
|
||||
"DistributionSetTag");
|
||||
verifyThrownExceptionBy(() -> distributionSetTagManagement.findByDistributionSet(NOT_EXIST_IDL, PAGE), "DistributionSet");
|
||||
verifyThrownExceptionBy(() -> distributionSetTagManagement.update(
|
||||
DistributionSetTagManagement.Update.builder().id(NOT_EXIST_IDL).build()), "DistributionSetTag");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,11 +85,11 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Collection<DistributionSet> dsBCs = testdataFactory.createDistributionSets("DS-BC", 13);
|
||||
final Collection<DistributionSet> dsABCs = testdataFactory.createDistributionSets("DS-ABC", 9);
|
||||
|
||||
final DistributionSetTag tagA = distributionSetTagManagement.create(entityFactory.tag().create().name("A"));
|
||||
final DistributionSetTag tagB = distributionSetTagManagement.create(entityFactory.tag().create().name("B"));
|
||||
final DistributionSetTag tagC = distributionSetTagManagement.create(entityFactory.tag().create().name("C"));
|
||||
final DistributionSetTag tagX = distributionSetTagManagement.create(entityFactory.tag().create().name("X"));
|
||||
final DistributionSetTag tagY = distributionSetTagManagement.create(entityFactory.tag().create().name("Y"));
|
||||
final DistributionSetTag tagA = distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("A").build());
|
||||
final DistributionSetTag tagB = distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("B").build());
|
||||
final DistributionSetTag tagC = distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("C").build());
|
||||
final DistributionSetTag tagX = distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("X").build());
|
||||
final DistributionSetTag tagY = distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("Y").build());
|
||||
|
||||
assignTag(dsAs, tagA);
|
||||
assignTag(dsBs, tagB);
|
||||
@@ -148,13 +145,13 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Collection<DistributionSet> groupB = testdataFactory.createDistributionSets("unassigned", 20);
|
||||
|
||||
final DistributionSetTag tag = distributionSetTagManagement
|
||||
.create(entityFactory.tag().create().name("tag1").description("tagdesc1"));
|
||||
.create(DistributionSetTagManagement.Create.builder().name("tag1").description("tagdesc1").build());
|
||||
|
||||
// toggle A only -> A is now assigned
|
||||
List<DistributionSet> result = assignTag(groupA, tag);
|
||||
List<? extends DistributionSet> result = assignTag(groupA, tag);
|
||||
assertThat(result)
|
||||
.hasSize(20)
|
||||
.containsAll(distributionSetManagement.get(groupA.stream().map(DistributionSet::getId).toList()));
|
||||
.containsAll((Collection) distributionSetManagement.get(groupA.stream().map(DistributionSet::getId).toList()));
|
||||
assertThat(
|
||||
distributionSetManagement.findByTag(tag.getId(), Pageable.unpaged()).getContent().stream()
|
||||
.map(DistributionSet::getId)
|
||||
@@ -165,7 +162,7 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Collection<DistributionSet> groupAB = concat(groupA, groupB);
|
||||
// toggle A+B -> A is still assigned and B is assigned as well
|
||||
result = assignTag(groupAB, tag);
|
||||
assertThat(result)
|
||||
assertThat((List) result)
|
||||
.hasSize(40)
|
||||
.containsAll(distributionSetManagement.get(groupAB.stream().map(DistributionSet::getId).toList()));
|
||||
assertThat(
|
||||
@@ -177,7 +174,7 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
result = unassignTag(concat(groupA, groupB), tag);
|
||||
assertThat(result)
|
||||
.hasSize(40)
|
||||
.containsAll(distributionSetManagement.get(concat(groupB, groupA).stream().map(DistributionSet::getId).toList()));
|
||||
.containsAll((List) distributionSetManagement.get(concat(groupB, groupA).stream().map(DistributionSet::getId).toList()));
|
||||
assertThat(distributionSetManagement.findByTag(tag.getId(), Pageable.unpaged()).getContent()).isEmpty();
|
||||
}
|
||||
|
||||
@@ -187,7 +184,8 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void failOnMissingDs() {
|
||||
final Collection<Long> group = testdataFactory.createDistributionSets(5).stream().map(DistributionSet::getId).toList();
|
||||
final DistributionSetTag tag = distributionSetTagManagement.create(entityFactory.tag().create().name("tag1").description("tagdesc1"));
|
||||
final DistributionSetTag tag = distributionSetTagManagement.create(
|
||||
DistributionSetTagManagement.Create.builder().name("tag1").description("tagdesc1").build());
|
||||
final List<Long> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
@@ -217,7 +215,7 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void createDistributionSetTag() {
|
||||
final Tag tag = distributionSetTagManagement
|
||||
.create(entityFactory.tag().create().name("kai1").description("kai2").colour("colour"));
|
||||
.create(DistributionSetTagManagement.Create.builder().name("kai1").description("kai2").colour("colour").build());
|
||||
|
||||
assertThat(distributionSetTagRepository.findByNameEquals("kai1").get().getDescription()).as("wrong tag found")
|
||||
.isEqualTo("kai2");
|
||||
@@ -261,7 +259,7 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void failedDuplicateDsTagNameException() {
|
||||
final TagCreate tag = entityFactory.tag().create().name("A");
|
||||
final DistributionSetTagManagement.Create tag = DistributionSetTagManagement.Create.builder().name("A").build();
|
||||
distributionSetTagManagement.create(tag);
|
||||
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class).as("should not have worked as tag already exists")
|
||||
@@ -273,10 +271,10 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void failedDuplicateDsTagNameExceptionAfterUpdate() {
|
||||
distributionSetTagManagement.create(entityFactory.tag().create().name("A"));
|
||||
final DistributionSetTag tag = distributionSetTagManagement.create(entityFactory.tag().create().name("B"));
|
||||
distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("A").build());
|
||||
final DistributionSetTag tag = distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder().name("B").build());
|
||||
|
||||
final TagUpdate tagUpdate = entityFactory.tag().update(tag.getId()).name("A");
|
||||
final DistributionSetTagManagement.Update tagUpdate = DistributionSetTagManagement.Update.builder().id(tag.getId()).name("A").build();
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class).as("should not have worked as tag already exists")
|
||||
.isThrownBy(() -> distributionSetTagManagement.update(tagUpdate));
|
||||
}
|
||||
@@ -291,7 +289,7 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
// change data
|
||||
final DistributionSetTag savedAssigned = tags.iterator().next();
|
||||
// persist
|
||||
distributionSetTagManagement.update(entityFactory.tag().update(savedAssigned.getId()).name("test123"));
|
||||
distributionSetTagManagement.update(DistributionSetTagManagement.Update.builder().id(savedAssigned.getId()).name("test123").build());
|
||||
// check data
|
||||
assertThat(distributionSetTagManagement.findAll(PAGE).getContent()).as("Wrong size of ds tags")
|
||||
.hasSize(tags.size());
|
||||
@@ -337,7 +335,7 @@ class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
tags.forEach(tag -> assignTag(sets, tag));
|
||||
|
||||
return distributionSetTagManagement.findAll(PAGE).getContent();
|
||||
return distributionSetTagManagement.findAll(PAGE).getContent().stream().map(DistributionSetTag.class::cast).toList();
|
||||
}
|
||||
|
||||
private DistributionSetFilter.DistributionSetFilterBuilder getDistributionSetFilterBuilder() {
|
||||
|
||||
@@ -13,9 +13,8 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractRepositoryManagementSecurityTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -25,21 +24,21 @@ import org.junit.jupiter.api.Test;
|
||||
* Story: SecurityTests DistributionSetTypeManagement
|
||||
*/
|
||||
class DistributionSetTypeManagementSecurityTest
|
||||
extends AbstractRepositoryManagementSecurityTest<DistributionSetType, DistributionSetTypeCreate, DistributionSetTypeUpdate> {
|
||||
extends AbstractRepositoryManagementSecurityTest<DistributionSetType, DistributionSetTypeManagement.Create, DistributionSetTypeManagement.Update> {
|
||||
|
||||
@Override
|
||||
protected RepositoryManagement<DistributionSetType, DistributionSetTypeCreate, DistributionSetTypeUpdate> getRepositoryManagement() {
|
||||
protected RepositoryManagement getRepositoryManagement() {
|
||||
return distributionSetTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DistributionSetTypeCreate getCreateObject() {
|
||||
return entityFactory.distributionSetType().create().key(String.format("key-%d", new Random().nextInt())).name(String.format("name-%d", new Random().nextInt()));
|
||||
protected DistributionSetTypeManagement.Create getCreateObject() {
|
||||
return DistributionSetTypeManagement.Create.builder().key(String.format("key-%d", new Random().nextInt())).name(String.format("name-%d", new Random().nextInt())).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DistributionSetTypeUpdate getUpdateObject() {
|
||||
return entityFactory.distributionSetType().update(1L).description("description");
|
||||
protected DistributionSetTypeManagement.Update getUpdateObject() {
|
||||
return DistributionSetTypeManagement.Update.builder().id(1L).description("description").build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,4 +82,4 @@ class DistributionSetTypeManagementSecurityTest
|
||||
void unassignSoftwareModuleTypePermissionsCheck() {
|
||||
assertPermissions(() -> distributionSetTypeManagement.unassignSoftwareModuleType(1L, 1L), List.of(SpPermission.UPDATE_REPOSITORY));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,8 @@ import java.util.Set;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
||||
@@ -90,8 +89,8 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
verifyThrownExceptionBy(() -> distributionSetTypeManagement.delete(NOT_EXIST_IDL), "DistributionSetType");
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> distributionSetTypeManagement.update(entityFactory.distributionSetType().update(NOT_EXIST_IDL)),
|
||||
"DistributionSet");
|
||||
() -> distributionSetTypeManagement.update(DistributionSetTypeManagement.Update.builder().id(NOT_EXIST_IDL).build()),
|
||||
"DistributionSetType");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +115,7 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void updateUnassignedDistributionSetTypeModules() {
|
||||
final DistributionSetType updatableType = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("updatableType").name("to be deleted"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("updatableType").name("to be deleted").build());
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").get().getMandatoryModuleTypes()).isEmpty();
|
||||
|
||||
// add OS
|
||||
@@ -146,14 +145,14 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
// create software module types
|
||||
final List<Long> moduleTypeIds = new ArrayList<>();
|
||||
for (int i = 0; i < quota + 1; ++i) {
|
||||
final SoftwareModuleTypeCreate smCreate = entityFactory.softwareModuleType().create().name("smType_" + i)
|
||||
.description("smType_" + i).maxAssignments(1).colour("blue").key("smType_" + i);
|
||||
final SoftwareModuleTypeManagement.Create smCreate = SoftwareModuleTypeManagement.Create.builder().name("smType_" + i)
|
||||
.description("smType_" + i).maxAssignments(1).colour("blue").key("smType_" + i).build();
|
||||
moduleTypeIds.add(softwareModuleTypeManagement.create(smCreate).getId());
|
||||
}
|
||||
|
||||
// assign all types at once
|
||||
final DistributionSetType dsType1 = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("dst1").name("dst1"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("dst1").name("dst1").build());
|
||||
final Long dsType1Id = dsType1.getId();
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.isThrownBy(() -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType1Id, moduleTypeIds));
|
||||
@@ -162,7 +161,7 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// assign as many mandatory modules as possible
|
||||
final DistributionSetType dsType2 = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("dst2").name("dst2"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("dst2").name("dst2").build());
|
||||
final Long dsType2Id = dsType2.getId();
|
||||
distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType2Id,
|
||||
moduleTypeIds.subList(0, quota));
|
||||
@@ -175,7 +174,7 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// assign as many optional modules as possible
|
||||
final DistributionSetType dsType3 = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("dst3").name("dst3"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("dst3").name("dst3").build());
|
||||
final Long dsType3Id = dsType3.getId();
|
||||
distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType3Id, moduleTypeIds.subList(0, quota));
|
||||
assertThat(distributionSetTypeManagement.get(dsType3Id)).isNotEmpty();
|
||||
@@ -194,11 +193,10 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSetType nonUpdatableType = createDistributionSetTypeUsedByDs();
|
||||
|
||||
distributionSetTypeManagement.update(
|
||||
entityFactory.distributionSetType().update(nonUpdatableType.getId()).description("a new description"));
|
||||
DistributionSetTypeManagement.Update.builder().id(nonUpdatableType.getId()).description("a new description").build());
|
||||
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").get().getDescription())
|
||||
.isEqualTo("a new description");
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").get().getColour()).isEqualTo("test123");
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").orElseThrow().getDescription()).isEqualTo("a new description");
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").orElseThrow().getColour()).isEqualTo("test123");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,13 +217,13 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void removeModuleToAssignedDistributionSetTypeFails() {
|
||||
DistributionSetType nonUpdatableType = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("updatableType").name("to be deleted"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("updatableType").name("to be deleted").build());
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").get().getMandatoryModuleTypes()).isEmpty();
|
||||
|
||||
final Long osTypeId = osType.getId();
|
||||
nonUpdatableType = distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(nonUpdatableType.getId(), Set.of(osTypeId));
|
||||
distributionSetManagement.create(
|
||||
entityFactory.distributionSet().create().name("newtypesoft").version("1").type(nonUpdatableType.getKey()));
|
||||
DistributionSetManagement.Create.builder().type(nonUpdatableType).name("newtypesoft").version("1").build());
|
||||
|
||||
final Long typeId = nonUpdatableType.getId();
|
||||
assertThatThrownBy(() -> distributionSetTypeManagement.unassignSoftwareModuleType(typeId, osTypeId))
|
||||
@@ -238,7 +236,7 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void deleteUnassignedDistributionSetType() {
|
||||
final JpaDistributionSetType hardDelete = (JpaDistributionSetType) distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("delete").name("to be deleted"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("delete").name("to be deleted").build());
|
||||
|
||||
assertThat(distributionSetTypeRepository.findAll()).contains(hardDelete);
|
||||
distributionSetTypeManagement.delete(hardDelete.getId());
|
||||
@@ -253,16 +251,16 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
void deleteAssignedDistributionSetType() {
|
||||
final int existing = (int) distributionSetTypeManagement.count();
|
||||
final JpaDistributionSetType toBeDeleted = (JpaDistributionSetType) distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("softdeleted").name("to be deleted"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("softdeleted").name("to be deleted").build());
|
||||
|
||||
assertThat(distributionSetTypeRepository.findAll()).contains(toBeDeleted);
|
||||
distributionSetManagement.create(
|
||||
entityFactory.distributionSet().create().name("softdeleted").version("1").type(toBeDeleted.getKey()));
|
||||
DistributionSetManagement.Create.builder().type(toBeDeleted).name("softdeleted").version("1").build());
|
||||
|
||||
distributionSetTypeManagement.delete(toBeDeleted.getId());
|
||||
final Optional<DistributionSetType> softdeleted = distributionSetTypeManagement.findByKey("softdeleted");
|
||||
assertThat(softdeleted).isPresent();
|
||||
assertThat(softdeleted.get().isDeleted()).isTrue();
|
||||
final Optional<? extends DistributionSetType> softDeleted = distributionSetTypeManagement.findByKey("softdeleted");
|
||||
assertThat(softDeleted).isPresent();
|
||||
assertThat(softDeleted.get().isDeleted()).isTrue();
|
||||
assertThat(distributionSetTypeManagement.findAll(PAGE)).hasSize(existing);
|
||||
assertThat(distributionSetTypeManagement.findByRsql("name==*", PAGE)).hasSize(existing);
|
||||
assertThat(distributionSetTypeManagement.count()).isEqualTo(existing);
|
||||
@@ -273,9 +271,8 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void shouldFailWhenDistributionSetHasNoSoftwareModulesAssigned() {
|
||||
|
||||
final JpaDistributionSetType jpaDistributionSetType = (JpaDistributionSetType) distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("newType").name("new Type"));
|
||||
.create(DistributionSetTypeManagement.Create.builder().key("newType").name("new Type").build());
|
||||
|
||||
final List<SoftwareModule> softwareModules = new ArrayList<>();
|
||||
|
||||
@@ -286,103 +283,113 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void createAndUpdateDistributionSetWithInvalidDescription(final DistributionSet set) {
|
||||
final DistributionSetCreate distributionSetCreate = entityFactory.distributionSet().create()
|
||||
.name("a").version("a").description(randomString(513));
|
||||
final DistributionSetManagement.Create distributionSetCreate = DistributionSetManagement.Create.builder()
|
||||
.name("a").version("a").description(randomString(513)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too long description should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate2 = entityFactory.distributionSet().create()
|
||||
.name("a").version("a").description(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Create distributionSetCreate2 = DistributionSetManagement.Create.builder()
|
||||
.name("a").version("a").description(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set invalid description text should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate2));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate = entityFactory.distributionSet().update(set.getId())
|
||||
.description(randomString(513));
|
||||
final DistributionSetManagement.Update distributionSetUpdate = DistributionSetManagement.Update.builder().id(set.getId())
|
||||
.description(randomString(513)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too long description should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate2 = entityFactory.distributionSet().update(set.getId()).description(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Update distributionSetUpdate2 = DistributionSetManagement.Update.builder().id(set.getId()).description(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with invalid description should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate2));
|
||||
}
|
||||
|
||||
private void createAndUpdateDistributionSetWithInvalidName(final DistributionSet set) {
|
||||
final DistributionSetCreate distributionSetCreate = entityFactory.distributionSet().create()
|
||||
.version("a").name(randomString(NamedEntity.NAME_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Create distributionSetCreate = DistributionSetManagement.Create.builder()
|
||||
.version("a").name(randomString(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too long name should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate2 = entityFactory.distributionSet().create().version("a").name(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Create distributionSetCreate2 =
|
||||
DistributionSetManagement.Create.builder().version("a").name(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with invalid name should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate2));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate3 = entityFactory.distributionSet().create().version("a").name("");
|
||||
final DistributionSetManagement.Create distributionSetCreate3 =
|
||||
DistributionSetManagement.Create.builder().version("a").name("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too short name should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate3));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate4 = entityFactory.distributionSet().create().version("a").name(null);
|
||||
final DistributionSetManagement.Create distributionSetCreate4 =
|
||||
DistributionSetManagement.Create.builder().version("a").name(null).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with null name should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate4));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate = entityFactory.distributionSet().update(set.getId())
|
||||
.name(randomString(NamedEntity.NAME_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Update distributionSetUpdate = DistributionSetManagement.Update.builder().id(set.getId())
|
||||
.name(randomString(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too long name should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate2 = entityFactory.distributionSet().update(set.getId()).name(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Update distributionSetUpdate2 =
|
||||
DistributionSetManagement.Update.builder().id(set.getId()).name(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with invalid name should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate2));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate3 = entityFactory.distributionSet().update(set.getId()).name("");
|
||||
final DistributionSetManagement.Update distributionSetUpdate3 =
|
||||
DistributionSetManagement.Update.builder().id(set.getId()).name("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too short name should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate3));
|
||||
}
|
||||
|
||||
private void createAndUpdateDistributionSetWithInvalidVersion(final DistributionSet set) {
|
||||
final DistributionSetCreate distributionSetCreate = entityFactory.distributionSet().create()
|
||||
.name("a").version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Create distributionSetCreate = DistributionSetManagement.Create.builder()
|
||||
.name("a").version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too long version should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate2 = entityFactory.distributionSet().create().name("a").version(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Create distributionSetCreate2 =
|
||||
DistributionSetManagement.Create.builder().name("a").version(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with invalid version should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate2));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate3 = entityFactory.distributionSet().create().name("a").version("");
|
||||
final DistributionSetManagement.Create distributionSetCreate3 =
|
||||
DistributionSetManagement.Create.builder().name("a").version("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too short version should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate3));
|
||||
|
||||
final DistributionSetCreate distributionSetCreate4 = entityFactory.distributionSet().create().name("a").version(null);
|
||||
final DistributionSetManagement.Create distributionSetCreate4 =
|
||||
DistributionSetManagement.Create.builder().name("a").version(null).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with null version should not be created")
|
||||
.isThrownBy(() -> distributionSetManagement.create(distributionSetCreate4));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate = entityFactory.distributionSet().update(set.getId())
|
||||
.version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1));
|
||||
final DistributionSetManagement.Update distributionSetUpdate = DistributionSetManagement.Update.builder().id(set.getId())
|
||||
.version(randomString(NamedVersionedEntity.VERSION_MAX_SIZE + 1)).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too long version should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate2 = entityFactory.distributionSet().update(set.getId()).version(INVALID_TEXT_HTML);
|
||||
final DistributionSetManagement.Update distributionSetUpdate2 =
|
||||
DistributionSetManagement.Update.builder().id(set.getId()).version(INVALID_TEXT_HTML).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with invalid version should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate2));
|
||||
|
||||
final DistributionSetUpdate distributionSetUpdate3 = entityFactory.distributionSet().update(set.getId()).version("");
|
||||
final DistributionSetManagement.Update distributionSetUpdate3 =
|
||||
DistributionSetManagement.Update.builder().id(set.getId()).version("").build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("set with too short version should not be updated")
|
||||
.isThrownBy(() -> distributionSetManagement.update(distributionSetUpdate3));
|
||||
@@ -390,10 +397,12 @@ class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private DistributionSetType createDistributionSetTypeUsedByDs() {
|
||||
final DistributionSetType nonUpdatableType = distributionSetTypeManagement.create(
|
||||
entityFactory.distributionSetType().create().key("updatableType").name("to be deleted").colour("test123"));
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").get().getMandatoryModuleTypes()).isEmpty();
|
||||
distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||
.name("newtypesoft").version("1").type(nonUpdatableType.getKey()));
|
||||
DistributionSetTypeManagement.Create.builder().key("updatableType").name("to be deleted").colour("test123").build());
|
||||
assertThat(distributionSetTypeManagement.findByKey("updatableType").orElseThrow().getMandatoryModuleTypes()).isEmpty();
|
||||
distributionSetManagement.create(DistributionSetManagement.Create.builder()
|
||||
.type(nonUpdatableType)
|
||||
.name("newtypesoft").version("1")
|
||||
.build());
|
||||
return nonUpdatableType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import jakarta.validation.ConstraintDeclarationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -25,11 +25,11 @@ import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
/**
|
||||
* Feature: SecurityTests - RolloutManagement<br/>
|
||||
* Story: SecurityTests RolloutManagement
|
||||
*/
|
||||
@Slf4j
|
||||
class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
@@ -101,9 +101,10 @@ class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void cancelRolloutsForDistributionSetPermissionsCheck() {
|
||||
final DistributionSetTypeCreate key = entityFactory.distributionSetType().create().name("type").key("type");
|
||||
final DistributionSetTypeManagement.Create key = DistributionSetTypeManagement.Create.builder().name("type").key("type").build();
|
||||
distributionSetTypeManagement.create(key);
|
||||
final DistributionSetCreate dsCreate = entityFactory.distributionSet().create().name("name").version("1.0.0").type("type");
|
||||
final DistributionSetManagement.Create dsCreate =
|
||||
DistributionSetManagement.Create.builder().type(defaultDsType()).name("name").version("1.0.0").build();
|
||||
final DistributionSet ds = distributionSetManagement.create(dsCreate);
|
||||
assertPermissions(() -> {
|
||||
rolloutManagement.cancelRolloutsForDistributionSet(ds);
|
||||
@@ -251,4 +252,4 @@ class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
void findByRolloutWithDetailedStatusPermissionsCheck() {
|
||||
assertPermissions(() -> rolloutGroupManagement.findByRolloutWithDetailedStatus(1L, PAGE), List.of(SpPermission.READ_ROLLOUT));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,7 @@ import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractRepositoryManagementSecurityTest;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -24,21 +23,21 @@ import org.junit.jupiter.api.Test;
|
||||
* Story: SecurityTests SoftwareManagement
|
||||
*/
|
||||
class SoftwareManagementSecurityTest
|
||||
extends AbstractRepositoryManagementSecurityTest<SoftwareModule, SoftwareModuleCreate, SoftwareModuleUpdate> {
|
||||
extends AbstractRepositoryManagementSecurityTest<SoftwareModule, SoftwareModuleManagement.Create, SoftwareModuleManagement.Update> {
|
||||
|
||||
@Override
|
||||
protected RepositoryManagement<SoftwareModule, SoftwareModuleCreate, SoftwareModuleUpdate> getRepositoryManagement() {
|
||||
protected RepositoryManagement getRepositoryManagement() {
|
||||
return softwareModuleManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleCreate getCreateObject() {
|
||||
return entityFactory.softwareModule().create().name("name").version("version").type("type");
|
||||
protected SoftwareModuleManagement.Create getCreateObject() {
|
||||
return SoftwareModuleManagement.Create.builder().type(getASmType()).name("name").version("version").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleUpdate getUpdateObject() {
|
||||
return entityFactory.softwareModule().update(1L).locked(true);
|
||||
protected SoftwareModuleManagement.Update getUpdateObject() {
|
||||
return SoftwareModuleManagement.Update.builder().id(1L).locked(true).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,5 +169,4 @@ class SoftwareManagementSecurityTest
|
||||
assertPermissions(() -> softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(List.of(1L)),
|
||||
List.of(SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,10 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
@@ -61,7 +65,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
private static final PageRequest PAGE_REQUEST_100 = PageRequest.of(0, 100);
|
||||
|
||||
/**
|
||||
* Verifies that management get access reacts as specified on calls for non existing entities by means
|
||||
* Verifies that management get access reacts as specified on calls for non existing entities by means
|
||||
* of Optional not present.
|
||||
*/
|
||||
@Test
|
||||
@@ -79,20 +83,19 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that management queries react as specfied on calls for non existing entities
|
||||
* by means of throwing EntityNotFoundException.
|
||||
* Verifies that management queries react as specfied on calls for non existing entities
|
||||
* by means of throwing EntityNotFoundException.
|
||||
*/
|
||||
@Test
|
||||
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
||||
void entityQueriesReferringToNotExistingEntitiesThrowsException() {
|
||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleManagement.create(Collections
|
||||
.singletonList(entityFactory.softwareModule().create().name("xxx").type(NOT_EXIST_ID))), "SoftwareModuleType");
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().name("xxx").type(NOT_EXIST_ID)), "SoftwareModuleType");
|
||||
final SoftwareModuleManagement.Create noType = SoftwareModuleManagement.Create.builder().name("xxx").type(null).build();
|
||||
final List<SoftwareModuleManagement.Create> noTypeList = List.of(noType);
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.create(noTypeList));
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> softwareModuleManagement.create(noType));
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleManagement.updateMetadata(
|
||||
@@ -122,7 +125,8 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.getMetadata(NOT_EXIST_IDL), "SoftwareModule");
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.findByType(NOT_EXIST_IDL, PAGE), "SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.update(entityFactory.softwareModule().update(NOT_EXIST_IDL)), "SoftwareModule");
|
||||
verifyThrownExceptionBy(() -> softwareModuleManagement.update(SoftwareModuleManagement.Update.builder().id(NOT_EXIST_IDL).build()),
|
||||
"SoftwareModule");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +137,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
final SoftwareModule updated = softwareModuleManagement
|
||||
.update(entityFactory.softwareModule().update(ah.getId()));
|
||||
.update(SoftwareModuleManagement.Update.builder().id(ah.getId()).build());
|
||||
|
||||
assertThat(updated.getOptLockRevision())
|
||||
.as("Expected version number of updated entity to be equal to created version")
|
||||
@@ -148,7 +152,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
final SoftwareModule updated = softwareModuleManagement
|
||||
.update(entityFactory.softwareModule().update(ah.getId()).description("changed").vendor("changed"));
|
||||
.update(SoftwareModuleManagement.Update.builder().id(ah.getId()).description("changed").vendor("changed").build());
|
||||
|
||||
assertThat(updated.getOptLockRevision())
|
||||
.as("Expected version number of updated entitity is")
|
||||
@@ -174,17 +178,20 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void findSoftwareModuleByFilters() {
|
||||
final SoftwareModule ah = softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(appType).name("agent-hub").version("1.0.1"));
|
||||
.create(SoftwareModuleManagement.Create.builder().type(appType).name("agent-hub").version("1.0.1").build());
|
||||
final SoftwareModule jvm = softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(runtimeType).name("oracle-jre").version("1.7.2"));
|
||||
.create(SoftwareModuleManagement.Create.builder().type(runtimeType).name("oracle-jre").version("1.7.2").build());
|
||||
final SoftwareModule os = softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(osType).name("poky").version("3.0.2"));
|
||||
.create(SoftwareModuleManagement.Create.builder().type(osType).name("poky").version("3.0.2").build());
|
||||
|
||||
final SoftwareModule ah2 = softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(appType).name("agent-hub").version("1.0.2"));
|
||||
.create(SoftwareModuleManagement.Create.builder().type(appType).name("agent-hub").version("1.0.2").build());
|
||||
JpaDistributionSet ds = (JpaDistributionSet) distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("ds-1").version("1.0.1").type(standardDsType)
|
||||
.modules(Arrays.asList(os.getId(), jvm.getId(), ah2.getId())));
|
||||
.create(DistributionSetManagement.Create.builder()
|
||||
.type(standardDsType)
|
||||
.name("ds-1").version("1.0.1")
|
||||
.modules(Set.of(os, jvm, ah2))
|
||||
.build());
|
||||
|
||||
final JpaTarget target = (JpaTarget) testdataFactory.createTarget();
|
||||
ds = (JpaDistributionSet) assignSet(target, ds).getDistributionSet();
|
||||
@@ -217,10 +224,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void findSoftwareModulesById() {
|
||||
|
||||
final List<Long> modules = Arrays.asList(testdataFactory.createSoftwareModuleOs().getId(),
|
||||
testdataFactory.createSoftwareModuleApp().getId(), 624355263L);
|
||||
|
||||
final List<Long> modules = List.of(testdataFactory.createSoftwareModuleOs().getId(), testdataFactory.createSoftwareModuleApp().getId());
|
||||
assertThat(softwareModuleManagement.get(modules)).hasSize(2);
|
||||
}
|
||||
|
||||
@@ -236,7 +240,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
softwareModuleManagement.delete(testdataFactory.createSoftwareModuleOs("deleted").getId());
|
||||
testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
assertThat(softwareModuleManagement.findByType(osType.getId(), PAGE).getContent())
|
||||
assertThat((List) softwareModuleManagement.findByType(osType.getId(), PAGE).getContent())
|
||||
.as("Expected to find the following number of modules:").hasSize(2).as("with the following elements")
|
||||
.contains(two, one);
|
||||
}
|
||||
@@ -497,8 +501,9 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// one soft deleted
|
||||
final SoftwareModule deleted = testdataFactory.createSoftwareModuleApp();
|
||||
final DistributionSet set = distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||
.name("set").version("1").modules(Arrays.asList(one.getId(), deleted.getId())));
|
||||
final DistributionSet set = distributionSetManagement.create(DistributionSetManagement.Create.builder()
|
||||
.type(defaultDsType())
|
||||
.name("set").version("1").modules(Set.of(one, deleted)).build());
|
||||
softwareModuleManagement.delete(deleted.getId());
|
||||
|
||||
assertThat(softwareModuleManagement.findByAssignedTo(set.getId(), PAGE).getContent())
|
||||
@@ -825,7 +830,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
final List<SoftwareModule> modules = distributionSet.getModules().stream().toList();
|
||||
assertThat(modules).hasSizeGreaterThan(1);
|
||||
|
||||
// try delete while DS is not locked
|
||||
// try to delete while DS is not locked
|
||||
softwareModuleManagement.delete(modules.get(0).getId());
|
||||
|
||||
distributionSetManagement.lock(distributionSet.getId());
|
||||
@@ -833,7 +838,7 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
distributionSetManagement.get(distributionSet.getId()).map(DistributionSet::isLocked).orElse(false))
|
||||
.isTrue();
|
||||
|
||||
// try delete SM of a locked DS
|
||||
// try to delete SM of a locked DS
|
||||
final Long moduleId = modules.get(1).getId();
|
||||
assertThatExceptionOfType(LockedException.class)
|
||||
.as("Attempt to delete a software module of a locked DS should throw an exception")
|
||||
@@ -865,8 +870,8 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
final long countSoftwareModule = softwareModuleRepository.count();
|
||||
|
||||
// create SoftwareModule
|
||||
SoftwareModule softwareModule = softwareModuleManagement.create(entityFactory.softwareModule().create()
|
||||
.type(type).name(name).version(version).description("description of artifact " + name));
|
||||
SoftwareModule softwareModule = softwareModuleManagement.create(SoftwareModuleManagement.Create.builder()
|
||||
.type(type).name(name).version(version).description("description of artifact " + name).build());
|
||||
|
||||
final int artifactSize = 5 * 1024;
|
||||
for (int i = 0; i < numberArtifacts; i++) {
|
||||
@@ -904,4 +909,4 @@ class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
.isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,7 @@ import java.util.Random;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.RepositoryManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractRepositoryManagementSecurityTest;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -25,21 +24,21 @@ import org.junit.jupiter.api.Test;
|
||||
* Story: SecurityTests SoftwareModuleTypeManagement
|
||||
*/
|
||||
class SoftwareModuleTypeManagementSecurityTest
|
||||
extends AbstractRepositoryManagementSecurityTest<SoftwareModuleType, SoftwareModuleTypeCreate, SoftwareModuleTypeUpdate> {
|
||||
extends AbstractRepositoryManagementSecurityTest<SoftwareModuleType, SoftwareModuleTypeManagement.Create, SoftwareModuleTypeManagement.Update> {
|
||||
|
||||
@Override
|
||||
protected RepositoryManagement<SoftwareModuleType, SoftwareModuleTypeCreate, SoftwareModuleTypeUpdate> getRepositoryManagement() {
|
||||
protected RepositoryManagement getRepositoryManagement() {
|
||||
return softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleTypeCreate getCreateObject() {
|
||||
return entityFactory.softwareModuleType().create().key(String.format("key-%d", new Random().nextInt())).name(String.format("name-%d", new Random().nextInt()));
|
||||
protected SoftwareModuleTypeManagement.Create getCreateObject() {
|
||||
return SoftwareModuleTypeManagement.Create.builder().key(String.format("key-%d", new Random().nextInt())).name(String.format("name-%d", new Random().nextInt())).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleTypeUpdate getUpdateObject() {
|
||||
return entityFactory.softwareModuleType().update(1L).description("description");
|
||||
protected SoftwareModuleTypeManagement.Update getUpdateObject() {
|
||||
return SoftwareModuleTypeManagement.Update.builder().id(1L).description("description").build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,5 +56,4 @@ class SoftwareModuleTypeManagementSecurityTest
|
||||
void getByNamePermissionsCheck() {
|
||||
assertPermissions(() -> softwareModuleTypeManagement.findByName("name"), List.of(SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,8 @@ import java.util.List;
|
||||
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
@@ -26,6 +27,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
/**
|
||||
* Feature: Component Tests - Repository<br/>
|
||||
@@ -34,7 +36,7 @@ import org.junit.jupiter.api.Test;
|
||||
class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
* Verifies that management get access reacts as specfied on calls for non existing entities by means
|
||||
* Verifies that management get access reacts as specfied on calls for non existing entities by means
|
||||
* of Optional not present.
|
||||
*/
|
||||
@Test
|
||||
@@ -47,8 +49,8 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that management queries react as specfied on calls for non existing entities
|
||||
* by means of throwing EntityNotFoundException.
|
||||
* Verifies that management queries react as specfied on calls for non existing entities
|
||||
* by means of throwing EntityNotFoundException.
|
||||
*/
|
||||
@Test
|
||||
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 0) })
|
||||
@@ -56,7 +58,7 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
verifyThrownExceptionBy(() -> softwareModuleTypeManagement.delete(NOT_EXIST_IDL), "SoftwareModuleType");
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> softwareModuleTypeManagement.update(entityFactory.softwareModuleType().update(NOT_EXIST_IDL)),
|
||||
() -> softwareModuleTypeManagement.update(SoftwareModuleTypeManagement.Update.builder().id(NOT_EXIST_IDL).build()),
|
||||
"SoftwareModuleType");
|
||||
}
|
||||
|
||||
@@ -66,10 +68,10 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void updateNothingResultsInUnchangedRepositoryForType() {
|
||||
final SoftwareModuleType created = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("test-key").name("test-name"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().key("test-key").name("test-name").build());
|
||||
|
||||
final SoftwareModuleType updated = softwareModuleTypeManagement
|
||||
.update(entityFactory.softwareModuleType().update(created.getId()));
|
||||
.update(SoftwareModuleTypeManagement.Update.builder().id(created.getId()).build());
|
||||
|
||||
assertThat(updated.getOptLockRevision())
|
||||
.as("Expected version number of updated entitity to be equal to created version")
|
||||
@@ -82,10 +84,10 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void updateSoftwareModuleTypeFieldsToNewValue() {
|
||||
final SoftwareModuleType created = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("test-key").name("test-name"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().key("test-key").name("test-name").build());
|
||||
|
||||
final SoftwareModuleType updated = softwareModuleTypeManagement.update(
|
||||
entityFactory.softwareModuleType().update(created.getId()).description("changed").colour("changed"));
|
||||
SoftwareModuleTypeManagement.Update.builder().id(created.getId()).description("changed").colour("changed").build());
|
||||
|
||||
assertThat(updated.getOptLockRevision()).as("Expected version number of updated entities is")
|
||||
.isEqualTo(created.getOptLockRevision() + 1);
|
||||
@@ -98,9 +100,9 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createModuleTypesCallFailsForExistingTypes() {
|
||||
final List<SoftwareModuleTypeCreate> created = Arrays.asList(
|
||||
entityFactory.softwareModuleType().create().key("test-key").name("test-name"),
|
||||
entityFactory.softwareModuleType().create().key("test-key2").name("test-name2"));
|
||||
final List<SoftwareModuleTypeManagement.Create> created = Arrays.asList(
|
||||
SoftwareModuleTypeManagement.Create.builder().key("test-key").name("test-name").build(),
|
||||
SoftwareModuleTypeManagement.Create.builder().key("test-key2").name("test-name2").build());
|
||||
softwareModuleTypeManagement.create(created);
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class)
|
||||
.as("should not have worked as module type already exists")
|
||||
@@ -112,32 +114,30 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void deleteAssignedAndUnassignedSoftwareModuleTypes() {
|
||||
assertThat(softwareModuleTypeManagement.findAll(PAGE)).hasSize(3).contains(osType, runtimeType, appType);
|
||||
assertThat((Slice) softwareModuleTypeManagement.findAll(PAGE)).hasSize(3).contains(osType, runtimeType, appType);
|
||||
|
||||
SoftwareModuleType type = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("bundle").name("OSGi Bundle"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().key("bundle").name("OSGi Bundle").build());
|
||||
|
||||
assertThat(softwareModuleTypeManagement.findAll(PAGE)).hasSize(4).contains(osType, runtimeType, appType, type);
|
||||
assertThat((Slice) softwareModuleTypeManagement.findAll(PAGE)).hasSize(4).contains(osType, runtimeType, appType, type);
|
||||
|
||||
// delete unassigned
|
||||
softwareModuleTypeManagement.delete(type.getId());
|
||||
assertThat(softwareModuleTypeManagement.findAll(PAGE)).hasSize(3).contains(osType, runtimeType, appType);
|
||||
assertThat(softwareModuleTypeRepository.findAll()).hasSize(3).contains((JpaSoftwareModuleType) osType,
|
||||
(JpaSoftwareModuleType) runtimeType, (JpaSoftwareModuleType) appType);
|
||||
assertThat((Slice) softwareModuleTypeManagement.findAll(PAGE)).hasSize(3).contains(osType, runtimeType, appType);
|
||||
assertThat((List) softwareModuleTypeRepository.findAll()).hasSize(3).contains(osType, runtimeType, appType);
|
||||
|
||||
type = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("bundle2").name("OSGi Bundle2"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().key("bundle2").name("OSGi Bundle2").build());
|
||||
|
||||
assertThat(softwareModuleTypeManagement.findAll(PAGE)).hasSize(4).contains(osType, runtimeType, appType, type);
|
||||
assertThat((Slice) softwareModuleTypeManagement.findAll(PAGE)).hasSize(4).contains(osType, runtimeType, appType, type);
|
||||
|
||||
softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(type).name("Test SM").version("1.0"));
|
||||
.create(SoftwareModuleManagement.Create.builder().type(type).name("Test SM").version("1.0").build());
|
||||
|
||||
// delete assigned
|
||||
softwareModuleTypeManagement.delete(type.getId());
|
||||
assertThat(softwareModuleTypeManagement.findAll(PAGE)).hasSize(3).contains(osType, runtimeType, appType);
|
||||
assertThat(softwareModuleTypeManagement.findByRsql("name==*", PAGE)).hasSize(3).contains(osType, runtimeType,
|
||||
appType);
|
||||
assertThat((Slice) softwareModuleTypeManagement.findAll(PAGE)).hasSize(3).contains(osType, runtimeType, appType);
|
||||
assertThat((Slice) softwareModuleTypeManagement.findByRsql("name==*", PAGE)).hasSize(3).contains(osType, runtimeType, appType);
|
||||
assertThat(softwareModuleTypeManagement.count()).isEqualTo(3);
|
||||
|
||||
assertThat(softwareModuleTypeRepository.findAll()).hasSize(4).contains((JpaSoftwareModuleType) osType,
|
||||
@@ -152,11 +152,12 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
void findSoftwareModuleTypeByName() {
|
||||
testdataFactory.createSoftwareModuleOs();
|
||||
final SoftwareModuleType found = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("thetype").name("thename"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().key("thetype").name("thename").build());
|
||||
softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("thetype2").name("anothername"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().key("thetype2").name("anothername").build());
|
||||
|
||||
assertThat(softwareModuleTypeManagement.findByName("thename")).as("Type with given name").contains(found);
|
||||
assertThat((((SoftwareModuleTypeManagement<SoftwareModuleType>) softwareModuleTypeManagement)).findByName("thename")).as(
|
||||
"Type with given name").contains(found);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,12 +165,11 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createSoftwareModuleTypeFailsWithExistingEntity() {
|
||||
final SoftwareModuleTypeCreate create = entityFactory.softwareModuleType().create().key("thetype").name("thename");
|
||||
final SoftwareModuleTypeManagement.Create create = SoftwareModuleTypeManagement.Create.builder().key("thetype").name("thename").build();
|
||||
softwareModuleTypeManagement.create(create);
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class)
|
||||
.as("should not have worked as module type already exists")
|
||||
.isThrownBy(() -> softwareModuleTypeManagement
|
||||
.create(create));
|
||||
.isThrownBy(() -> softwareModuleTypeManagement.create(create));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,10 +177,10 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createSoftwareModuleTypesFailsWithExistingEntity() {
|
||||
softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create().key("thetype").name("thename"));
|
||||
final List<SoftwareModuleTypeCreate> creates = List.of(
|
||||
entityFactory.softwareModuleType().create().key("thetype").name("thename"),
|
||||
entityFactory.softwareModuleType().create().key("anothertype").name("anothername"));
|
||||
softwareModuleTypeManagement.create(SoftwareModuleTypeManagement.Create.builder().key("thetype").name("thename").build());
|
||||
final List<SoftwareModuleTypeManagement.Create> creates = List.of(
|
||||
SoftwareModuleTypeManagement.Create.builder().key("thetype").name("thename").build(),
|
||||
SoftwareModuleTypeManagement.Create.builder().key("anothertype").name("anothername").build());
|
||||
assertThatExceptionOfType(EntityAlreadyExistsException.class)
|
||||
.as("should not have worked as module type already exists")
|
||||
.isThrownBy(() -> softwareModuleTypeManagement.create(creates));
|
||||
@@ -191,7 +191,8 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createSoftwareModuleTypesFailsWithInvalidMaxAssignment() {
|
||||
final SoftwareModuleTypeCreate create = entityFactory.softwareModuleType().create().key("type").name("name").maxAssignments(0);
|
||||
final SoftwareModuleTypeManagement.Create create =
|
||||
SoftwareModuleTypeManagement.Create.builder().key("type").name("name").maxAssignments(0).build();
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.as("should not have worked as max assignment is invalid. Should be greater than 0")
|
||||
.isThrownBy(() -> softwareModuleTypeManagement.create(create));
|
||||
@@ -202,12 +203,12 @@ class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void createMultipleSoftwareModuleTypes() {
|
||||
final List<SoftwareModuleType> created = softwareModuleTypeManagement
|
||||
.create(Arrays.asList(entityFactory.softwareModuleType().create().key("thetype").name("thename"),
|
||||
entityFactory.softwareModuleType().create().key("thetype2").name("thename2")));
|
||||
final List<? extends SoftwareModuleType> created = softwareModuleTypeManagement
|
||||
.create(List.of(
|
||||
SoftwareModuleTypeManagement.Create.builder().key("thetype").name("thename").build(),
|
||||
SoftwareModuleTypeManagement.Create.builder().key("thetype2").name("thename2").build()));
|
||||
|
||||
assertThat(created).as("Number of created types").hasSize(2);
|
||||
assertThat(softwareModuleTypeManagement.count()).as("Number of types in repository").isEqualTo(5);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@ import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
/**
|
||||
* Feature: SecurityTests - SystemManagement<br/>
|
||||
* Story: SecurityTests SystemManagement
|
||||
*/
|
||||
@Slf4j
|
||||
class SystemManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@ import jakarta.validation.ConstraintViolationException;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
@@ -588,8 +589,10 @@ class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private void verifyAutoAssignmentWithIncompleteDs(final TargetFilterQuery targetFilterQuery) {
|
||||
final DistributionSet incompleteDistributionSet = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("incomplete").version("1")
|
||||
.type(testdataFactory.findOrCreateDefaultTestDsType()));
|
||||
.create(DistributionSetManagement.Create.builder()
|
||||
.type(testdataFactory.findOrCreateDefaultTestDsType())
|
||||
.name("incomplete").version("1")
|
||||
.build());
|
||||
|
||||
final AutoAssignDistributionSetUpdate autoAssignDistributionSetUpdate = entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(incompleteDistributionSet.getId());
|
||||
|
||||
@@ -16,8 +16,8 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -62,7 +62,7 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests different parameter combinations for target search operations.
|
||||
* Tests different parameter combinations for target search operations.
|
||||
* and query definitions by RSQL (named and un-named).
|
||||
*/
|
||||
@Test
|
||||
@@ -278,13 +278,12 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void shouldNotFindTargetsIncompatibleWithDS() {
|
||||
final DistributionSetType dsType = testdataFactory.findOrCreateDistributionSetType("test-ds-type",
|
||||
"test-ds-type");
|
||||
final DistributionSet testDs = createDistSetWithType(dsType);
|
||||
final TargetType compatibleTargetType = testdataFactory.createTargetType("compTestType",
|
||||
Collections.singletonList(dsType));
|
||||
final TargetType incompatibleTargetType = testdataFactory.createTargetType("incompTestType",
|
||||
Collections.singletonList(testdataFactory.createDistributionSet().getType()));
|
||||
final DistributionSetType dsType = testdataFactory.findOrCreateDistributionSetType("test-ds-type", "test-ds-type");
|
||||
final DistributionSet testDs = distributionSetManagement.create(DistributionSetManagement.Create.builder()
|
||||
.type(dsType).name("test-ds").version("1.0").build());
|
||||
final TargetType compatibleTargetType = testdataFactory.createTargetType("compTestType", List.of(dsType));
|
||||
final TargetType incompatibleTargetType = testdataFactory.createTargetType(
|
||||
"incompTestType", List.of(testdataFactory.createDistributionSet().getType()));
|
||||
final TargetFilterQuery tfq = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("test-filter").query("name==*"));
|
||||
|
||||
@@ -659,10 +658,4 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.hasSize((int) targetManagement.countByFilters(filterParams))
|
||||
.as("and contains the following elements").containsAll(expected);
|
||||
}
|
||||
|
||||
private DistributionSet createDistSetWithType(final DistributionSetType type) {
|
||||
final DistributionSetCreate dsCreate = entityFactory.distributionSet().create().name("test-ds").version("1.0")
|
||||
.type(type);
|
||||
return distributionSetManagement.create(dsCreate);
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,11 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
/**
|
||||
* Feature: SecurityTests - TargetManagement<br/>
|
||||
* Story: SecurityTests TargetManagement
|
||||
*/
|
||||
@Slf4j
|
||||
class TargetManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
@@ -184,9 +184,9 @@ class TargetManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void findByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatablePermissionsCheck() {
|
||||
assertPermissions(
|
||||
() -> targetManagement.findByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(List.of(1L), "controllerId==id",
|
||||
entityFactory.distributionSetType().create().build(), PAGE
|
||||
), List.of(SpPermission.READ_TARGET, SpPermission.READ_ROLLOUT));
|
||||
() -> targetManagement.findByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
List.of(1L), "controllerId==id", defaultDsType(), PAGE),
|
||||
List.of(SpPermission.READ_TARGET, SpPermission.READ_ROLLOUT));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,8 +203,10 @@ class TargetManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatablePermissionsCheck() {
|
||||
assertPermissions(() -> targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable("controllerId==id", List.of(1L),
|
||||
entityFactory.distributionSetType().create().build()), List.of(SpPermission.READ_TARGET, SpPermission.READ_ROLLOUT));
|
||||
assertPermissions(
|
||||
() -> targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
"controllerId==id", List.of(1L), defaultDsType()),
|
||||
List.of(SpPermission.READ_TARGET, SpPermission.READ_ROLLOUT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,11 +16,11 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
/**
|
||||
* Feature: SecurityTests - TargetTagManagement<br/>
|
||||
* Story: SecurityTests TargetTagManagement
|
||||
*/
|
||||
@Slf4j
|
||||
class TargetTagManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
@@ -106,4 +106,4 @@ class TargetTagManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
void updatePermissionsCheck() {
|
||||
assertPermissions(() -> targetTagManagement.update(entityFactory.tag().update(1L)), List.of(SpPermission.UPDATE_TARGET));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,11 @@ import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
/**
|
||||
* Feature: SecurityTests - TargetTypeManagement<br/>
|
||||
* Story: SecurityTests TargetTypeManagement
|
||||
*/
|
||||
@Slf4j
|
||||
class TargetTypeManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
@@ -151,5 +151,4 @@ class TargetTypeManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
assertPermissions(() -> targetTypeManagement.unassignDistributionSetType(1L, 1L),
|
||||
List.of(SpPermission.UPDATE_TARGET, SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,11 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
/**
|
||||
* Feature: SecurityTests - TargetManagement<br/>
|
||||
* Story: SecurityTests TargetManagement
|
||||
*/
|
||||
@Slf4j
|
||||
class TenantConfigurationManagementSecurityTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
@@ -87,4 +87,4 @@ class TenantConfigurationManagementSecurityTest extends AbstractJpaIntegrationTe
|
||||
void pollStatusResolverPermissionsCheck() {
|
||||
assertPermissions(() -> tenantConfigurationManagement.pollStatusResolver(), List.of(SpPermission.READ_TARGET));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.EntityInterceptor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
|
||||
@@ -115,7 +116,7 @@ class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
|
||||
private void executeDeleteAndAssertCallbackResult(final AbstractEntityListener entityInterceptor) {
|
||||
EntityInterceptorHolder.getInstance().getEntityInterceptors().add(entityInterceptor);
|
||||
final SoftwareModuleType type = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().name("test").key("test"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().name("test").key("test").build());
|
||||
|
||||
softwareModuleTypeManagement.delete(type.getId());
|
||||
assertThat(entityInterceptor.getEntity()).isNotNull();
|
||||
@@ -198,4 +199,4 @@ class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
|
||||
setEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -59,12 +60,12 @@ class ModelEqualsHashcodeTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
void changedEntitiesAreNotEqual() {
|
||||
final SoftwareModuleType type = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("test").name("test"));
|
||||
.create(SoftwareModuleTypeManagement.Create.builder().key("test").name("test").build());
|
||||
assertThat(type).as("persited entity is not equal to regular object")
|
||||
.isNotEqualTo(entityFactory.softwareModuleType().create().key("test").name("test").build());
|
||||
.isNotEqualTo(SoftwareModuleTypeManagement.Create.builder().key("test").name("test").build());
|
||||
|
||||
final SoftwareModuleType updated = softwareModuleTypeManagement.update(
|
||||
entityFactory.softwareModuleType().update(type.getId()).description("another"));
|
||||
SoftwareModuleTypeManagement.Update.builder().id(type.getId()).description("another").build());
|
||||
assertThat(type).as("Changed entity is not equal to the previous version").isNotEqualTo(updated);
|
||||
}
|
||||
|
||||
@@ -72,9 +73,9 @@ class ModelEqualsHashcodeTest extends AbstractJpaIntegrationTest {
|
||||
* Verify that no proxy of the entity manager has an influence on the equals or hashcode result.
|
||||
*/
|
||||
@Test
|
||||
void managedEntityIsEqualToUnamangedObjectWithSameKey() {
|
||||
void managedEntityIsEqualToUnmanagedObjectWithSameKey() {
|
||||
final SoftwareModuleType type = softwareModuleTypeManagement.create(
|
||||
entityFactory.softwareModuleType().create().key("test").name("test").description("test"));
|
||||
SoftwareModuleTypeManagement.Create.builder().key("test").name("test").description("test").build());
|
||||
|
||||
final JpaSoftwareModuleType mock = new JpaSoftwareModuleType("test", "test", "test", 1);
|
||||
mock.setId(type.getId());
|
||||
@@ -86,5 +87,4 @@ class ModelEqualsHashcodeTest extends AbstractJpaIntegrationTest {
|
||||
.as("managed entity has same hash code as regular object with same content")
|
||||
.hasSameHashCodeAs(mock.hashCode());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
@@ -33,20 +34,20 @@ class RsqlSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@BeforeEach
|
||||
void setupBeforeTest() {
|
||||
ah = softwareModuleManagement.create(entityFactory.softwareModule().create().type(appType).name("agent-hub")
|
||||
.version("1.0.1").description("agent-hub"));
|
||||
softwareModuleManagement.create(entityFactory.softwareModule().create().type(runtimeType).name("oracle-jre")
|
||||
.version("1.7.2").description("aa"));
|
||||
ah = softwareModuleManagement.create(SoftwareModuleManagement.Create.builder().type(appType).name("agent-hub")
|
||||
.version("1.0.1").description("agent-hub").build());
|
||||
softwareModuleManagement.create(SoftwareModuleManagement.Create.builder().type(runtimeType).name("oracle-jre")
|
||||
.version("1.7.2").description("aa").build());
|
||||
softwareModuleManagement.create(
|
||||
entityFactory.softwareModule().create().type(osType).name("poki").version("3.0.2").description("aa"));
|
||||
SoftwareModuleManagement.Create.builder().type(osType).name("poki").version("3.0.2").description("aa").build());
|
||||
softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(osType).name("*§$%&/&%ÄÜ*Ö@").version("1.0.0")
|
||||
.description("wildcard testing"));
|
||||
.create(SoftwareModuleManagement.Create.builder().type(osType).name("*§$%&/&%ÄÜ*Ö@").version("1.0.0")
|
||||
.description("wildcard testing").build());
|
||||
softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(osType).name("noDesc").version("noDesc"));
|
||||
.create(SoftwareModuleManagement.Create.builder().type(osType).name("noDesc").version("noDesc").build());
|
||||
|
||||
final JpaSoftwareModule ah2 = (JpaSoftwareModule) softwareModuleManagement.create(entityFactory.softwareModule()
|
||||
.create().type(appType).name("agent-hub2").version("1.0.1").description("agent-hub2"));
|
||||
final JpaSoftwareModule ah2 = (JpaSoftwareModule) softwareModuleManagement.create(
|
||||
SoftwareModuleManagement.Create.builder().type(appType).name("agent-hub2").version("1.0.1").description("agent-hub2").build());
|
||||
|
||||
final SoftwareModuleMetadataCreate softwareModuleMetadata = entityFactory.softwareModuleMetadata()
|
||||
.create(ah.getId()).key("metaKey").value("metaValue");
|
||||
@@ -163,7 +164,7 @@ class RsqlSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void assertRSQLQuery(final String rsql, final long expectedEntity) {
|
||||
final Page<SoftwareModule> find = softwareModuleManagement.findByRsql(rsql, PageRequest.of(0, 100));
|
||||
final Page<? extends SoftwareModule> find = softwareModuleManagement.findByRsql(rsql, PageRequest.of(0, 100));
|
||||
final long countAll = find.getTotalElements();
|
||||
assertThat(find).isNotNull();
|
||||
assertThat(countAll).isEqualTo(expectedEntity);
|
||||
|
||||
@@ -87,9 +87,9 @@ class RsqlSoftwareModuleTypeFieldsTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void assertRSQLQuery(final String rsql, final long expectedEntity) {
|
||||
final Page<SoftwareModuleType> find = softwareModuleTypeManagement.findByRsql(rsql, PageRequest.of(0, 100));
|
||||
final Page<? extends SoftwareModuleType> find = softwareModuleTypeManagement.findByRsql(rsql, PageRequest.of(0, 100));
|
||||
final long countAll = find.getTotalElements();
|
||||
assertThat(find).isNotNull();
|
||||
assertThat(countAll).isEqualTo(expectedEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TagFields;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
@@ -29,12 +29,11 @@ class RsqlTagFieldsTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@BeforeEach
|
||||
void seuptBeforeTest() {
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final TagCreate targetTag = entityFactory.tag().create()
|
||||
.name(Integer.toString(i)).description(Integer.toString(i)).colour(i % 2 == 0 ? "red" : "blue");
|
||||
targetTagManagement.create(targetTag);
|
||||
distributionSetTagManagement.create(targetTag);
|
||||
targetTagManagement.create(entityFactory.tag().create()
|
||||
.name(Integer.toString(i)).description(Integer.toString(i)).colour(i % 2 == 0 ? "red" : "blue"));
|
||||
distributionSetTagManagement.create(DistributionSetTagManagement.Create.builder()
|
||||
.name(Integer.toString(i)).description(Integer.toString(i)).colour(i % 2 == 0 ? "red" : "blue").build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +128,9 @@ class RsqlTagFieldsTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void assertRSQLQueryDistributionSet(final String rsql, final long expectedEntities) {
|
||||
final Page<DistributionSetTag> findEnitity = distributionSetTagManagement.findByRsql(rsql, PageRequest.of(0, 100));
|
||||
final long countAllEntities = findEnitity.getTotalElements();
|
||||
assertThat(findEnitity).isNotNull();
|
||||
final Page<? extends DistributionSetTag> findEntity = distributionSetTagManagement.findByRsql(rsql, PageRequest.of(0, 100));
|
||||
final long countAllEntities = findEntity.getTotalElements();
|
||||
assertThat(findEntity).isNotNull();
|
||||
assertThat(countAllEntities).isEqualTo(expectedEntities);
|
||||
}
|
||||
|
||||
|
||||
@@ -167,11 +167,11 @@ class MultiTenancyEntityTest extends AbstractJpaIntegrationTest {
|
||||
createDistributionSetForTenant(anotherTenant);
|
||||
|
||||
// ensure both tenants see their distribution sets
|
||||
final Slice<DistributionSet> findDistributionSetsForTenant = findDistributionSetForTenant(tenant);
|
||||
final Slice<? extends DistributionSet> findDistributionSetsForTenant = findDistributionSetForTenant(tenant);
|
||||
assertThat(findDistributionSetsForTenant).hasSize(1);
|
||||
assertThat(findDistributionSetsForTenant.getContent().get(0).getTenant().toUpperCase())
|
||||
.isEqualTo(tenant.toUpperCase());
|
||||
final Slice<DistributionSet> findDistributionSetsForAnotherTenant = findDistributionSetForTenant(anotherTenant);
|
||||
final Slice<? extends DistributionSet> findDistributionSetsForAnotherTenant = findDistributionSetForTenant(anotherTenant);
|
||||
assertThat(findDistributionSetsForAnotherTenant).hasSize(1);
|
||||
assertThat(findDistributionSetsForAnotherTenant.getContent().get(0).getTenant().toUpperCase())
|
||||
.isEqualTo(anotherTenant.toUpperCase());
|
||||
@@ -200,7 +200,7 @@ class MultiTenancyEntityTest extends AbstractJpaIntegrationTest {
|
||||
return runAsTenant(tenant, () -> testdataFactory.createDistributionSet());
|
||||
}
|
||||
|
||||
private Slice<DistributionSet> findDistributionSetForTenant(final String tenant) throws Exception {
|
||||
private Slice<? extends DistributionSet> findDistributionSetForTenant(final String tenant) throws Exception {
|
||||
return runAsTenant(tenant, () -> distributionSetManagement.findByCompleted(true, PAGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user