JPA Refactoring (2) (#2108)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-12-02 11:52:30 +02:00
committed by GitHub
parent 2a95adc562
commit 794f26bea2
41 changed files with 691 additions and 483 deletions

View File

@@ -86,7 +86,8 @@ public final class JpaManagementHelper {
public static <J extends AbstractJpaBaseEntity> J touch(final EntityManager entityManager,
final CrudRepository<J, ?> repository, final J entity) {
// merge base entity so optLockRevision gets updated and auditing log written because modifying e.g. metadata is modifying the base
// merge base entity so optLockRevision gets updated and audit
// log written because modifying e.g. metadata is modifying the base
// entity itself for auditing purposes.
final J result = entityManager.merge(entity);
result.setLastModifiedAt(0L);

View File

@@ -42,9 +42,8 @@ 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.
* 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);
@@ -72,22 +71,18 @@ 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 {
// Workaround for EclipseLink merge where it does not throw ConstraintViolationException directly in case of
// existing entity update
// Workaround for EclipseLink merge where it does not throw ConstraintViolationException directly in case of existing entity update
if (ex instanceof TransactionSystemException) {
throw replaceWithCauseIfConstraintViolationException((TransactionSystemException) ex);
}
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);
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());

View File

@@ -51,7 +51,8 @@ public class JpaDistributionSetCreate extends AbstractDistributionSetUpdateCreat
@Override
public JpaDistributionSet build() {
return new JpaDistributionSet(name, version, description,
return new JpaDistributionSet(
name, version, description,
Optional.ofNullable(type).map(this::findDistributionSetTypeWithExceptionIfNotFound).orElse(null),
findSoftwareModuleWithExceptionIfNotFound(modules),
Optional.ofNullable(requiredMigrationStep).orElse(Boolean.FALSE));

View File

@@ -25,8 +25,7 @@ import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* {@link JpaTransactionManager} that sets the
* {@link TenantAware#getCurrentTenant()} in the eclipselink session. This has
* {@link JpaTransactionManager} that sets the {@link TenantAware#getCurrentTenant()} in the eclipselink session. This has
* to be done in eclipselink after a {@link Transaction} has been started.
*/
public class MultiTenantJpaTransactionManager extends JpaTransactionManager {

View File

@@ -66,8 +66,7 @@ public class JpaActionManagement {
}
protected List<JpaAction> findActiveActionsHavingStatus(final String controllerId, final Action.Status status) {
return actionRepository.findAll(
ActionSpecifications.byTargetControllerIdAndIsActiveAndStatus(controllerId, status));
return actionRepository.findAll(ActionSpecifications.byTargetControllerIdAndIsActiveAndStatus(controllerId, status));
}
protected Action addActionStatus(final JpaActionStatusCreate statusCreate) {

View File

@@ -64,20 +64,15 @@ import org.springframework.validation.annotation.Validated;
public class JpaDistributionSetTypeManagement implements DistributionSetTypeManagement {
private final DistributionSetTypeRepository distributionSetTypeRepository;
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
private final DistributionSetRepository distributionSetRepository;
private final TargetTypeRepository targetTypeRepository;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final Database database;
private final QuotaManagement quotaManagement;
public JpaDistributionSetTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
public JpaDistributionSetTypeManagement(
final DistributionSetTypeRepository distributionSetTypeRepository,
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,

View File

@@ -24,7 +24,6 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.CurrentTenantCacheKeyGenerator;
import org.eclipse.hawkbit.repository.jpa.SystemManagementCacheKeyGenerator;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData;
@@ -141,16 +140,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
return currentTenantCacheKeyGenerator.currentTenantKeyGenerator();
}
@Override
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager", unless = "#result == null")
public String currentTenant() {
return currentTenantCacheKeyGenerator.getTenantInCreation().orElseGet(() -> {
final TenantMetaData findByTenant = tenantMetaDataRepository
.findByTenantIgnoreCase(tenantAware.getCurrentTenant());
return findByTenant != null ? findByTenant.getTenant() : null;
});
}
@Override
@Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
@@ -295,6 +284,12 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
.orElseThrow(() -> new EntityNotFoundException(TenantMetaData.class, tenantId));
}
@Override
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager", unless = "#result == null")
public boolean tenantExists(final String tenant) {
return tenantMetaDataRepository.findByTenantIgnoreCase(tenant) != null;
}
private static boolean isPostgreSql(final JpaProperties properties) {
return Database.POSTGRESQL == properties.getDatabase();
}
@@ -342,13 +337,13 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
}
/**
* Creating the initial tenant meta-data in a new transaction. Due the
* {@link MultiTenantJpaTransactionManager} is using the current tenant to
* Creating the initial tenant meta-data in a new transaction. Due to the
* {@link org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager} is using the current tenant to
* set the necessary tenant discriminator to the query. This is not working
* if we don't have a current tenant set. Due the
* if we don't have a current tenant set. Due to the
* {@link #createTenantMetadata(String)} is maybe called without having a
* current tenant we need to re-open a new transaction so the
* {@link MultiTenantJpaTransactionManager} is called again and set the
* {@link org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager} is called again and set the
* tenant for this transaction.
*
* @param tenant the tenant to be created

View File

@@ -28,6 +28,7 @@ import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
import org.eclipse.persistence.annotations.Multitenant;
import org.eclipse.persistence.annotations.MultitenantType;
import org.eclipse.persistence.annotations.TenantDiscriminatorColumn;
import org.hibernate.annotations.TenantId;
/**
* Holder of the base attributes common to all tenant aware entities.
@@ -88,11 +89,14 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
/**
* PrePersist listener method for all {@link TenantAwareBaseEntity} entities.
*
* // TODO - check if the tenant support should set tenant from context
* // TODO - should we check if tenant exists in the system? Note: seems it's not good to work with db in the listener
*/
@PrePersist
void prePersist() {
// before persisting the entity check the current ID of the tenant by using the TenantAware service
final String currentTenant = SystemManagementHolder.getInstance().currentTenant();
final String currentTenant = TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant();
if (currentTenant == null) {
throw new TenantNotExistException(
String.format(

View File

@@ -71,7 +71,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
*/
@Modifying
@Transactional
@Query("UPDATE JpaAction a SET a.status = :statusToSet WHERE a.target IN :targetsIds AND a.active = :active AND a.status = :currentStatus AND a.distributionSet.requiredMigrationStep = false")
@Query("UPDATE JpaAction a SET a.status = :statusToSet WHERE a.target.id IN :targetsIds AND a.active = :active AND a.status = :currentStatus AND a.distributionSet.requiredMigrationStep = false")
void switchStatus(@Param("statusToSet") Action.Status statusToSet, @Param("targetsIds") List<Long> targetIds,
@Param("active") boolean active, @Param("currentStatus") Action.Status currentStatus);

View File

@@ -16,6 +16,7 @@ import java.util.Optional;
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.AbstractJpaTenantAwareBaseEntity;
@@ -65,6 +66,17 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
@Override
List<T> findAll();
/**
* Gets by id requiring entity to exists
*
* @param id the entity id
* @return the existing entity.
* @throws EntityNotFoundException if the entity doesn't exist
*/
default T getById(final Long id) {
return findById(id).orElseThrow(() -> new EntityNotFoundException(getDomainClass(), id));
}
/**
* Overrides
* {@link org.springframework.data.repository.CrudRepository#findAllById(Iterable)}