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
|
||||
|
||||
Reference in New Issue
Block a user