JPA Refactoring (3) (#2109)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-12-02 13:50:06 +02:00
committed by GitHub
parent 794f26bea2
commit a9f3d1491a
37 changed files with 151 additions and 246 deletions

View File

@@ -154,7 +154,6 @@ 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.EventPublisherHolder;
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
@@ -488,16 +487,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return TenantConfigurationManagementHolder.getInstance();
}
/**
* @return the {@link SystemManagementHolder} singleton bean which holds the
* current {@link SystemManagement} service and make it accessible in
* beans which cannot access the service directly, e.g. JPA entities.
*/
@Bean
SystemManagementHolder systemManagementHolder() {
return SystemManagementHolder.getInstance();
}
/**
* @return the {@link TenantAwareHolder} singleton bean which holds the current
* {@link TenantAware} service and make it accessible in beans which

View File

@@ -24,7 +24,6 @@ import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.AutoConfirmationAlreadyActiveException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException;
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
@@ -35,7 +34,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
@@ -81,7 +79,7 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
public AutoConfirmationStatus activateAutoConfirmation(final String controllerId, final String initiator, final String remark) {
log.trace(
"'activateAutoConfirmation' was called with values: controllerId={}; initiator={}; remark={}", controllerId, initiator, remark);
final JpaTarget target = getTargetByControllerIdAndThrowIfNotFound(controllerId);
final JpaTarget target = targetRepository.getByControllerId(controllerId);
if (target.getAutoConfirmationStatus() != null) {
log.debug("'activateAutoConfirmation' was called for an controller id {} with active auto confirmation.", controllerId);
throw new AutoConfirmationAlreadyActiveException(controllerId);
@@ -104,13 +102,13 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
@Override
public Optional<AutoConfirmationStatus> getStatus(final String controllerId) {
return Optional.of(getTargetByControllerIdAndThrowIfNotFound(controllerId)).map(JpaTarget::getAutoConfirmationStatus);
return Optional.of(targetRepository.getByControllerId(controllerId)).map(JpaTarget::getAutoConfirmationStatus);
}
@Override
@Transactional
public List<Action> autoConfirmActiveActions(final String controllerId) {
final JpaTarget target = getTargetByControllerIdAndThrowIfNotFound(controllerId);
final JpaTarget target = targetRepository.getByControllerId(controllerId);
if (target.getAutoConfirmationStatus() == null) {
// auto-confirmation is not active
return Collections.emptyList();
@@ -159,7 +157,7 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
@Transactional
public void deactivateAutoConfirmation(String controllerId) {
log.debug("Deactivate auto confirmation for controllerId '{}'", controllerId);
final JpaTarget target = getTargetByControllerIdAndThrowIfNotFound(controllerId);
final JpaTarget target = targetRepository.getByControllerId(controllerId);
target.setAutoConfirmationStatus(null);
targetRepository.save(target);
}
@@ -220,19 +218,12 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
"Automatically confirm actionId '{}' due to active auto-confirmation initiated by '{}' and rollouts system user '{}'",
action.getId(), autoConfirmationStatus.getInitiator(), autoConfirmationStatus.getCreatedBy());
// do not make use of
// org.eclipse.hawkbit.repository.jpa.management.JpaActionManagement.handleAddUpdateActionStatus
// to bypass the quota check. Otherwise, the action will not be confirmed in case
// of exceeded action status quota.
// do not make use of org.eclipse.hawkbit.repository.jpa.management.JpaActionManagement.handleAddUpdateActionStatus
// to bypass the quota check. Otherwise, the action will not be confirmed in case of exceeded action status quota.
action.setStatus(Status.RUNNING);
actionStatus.setAction(action);
actionStatusRepository.save(actionStatus);
return actionRepository.save(action);
}
private JpaTarget getTargetByControllerIdAndThrowIfNotFound(final String controllerId) {
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
}
}

View File

@@ -414,8 +414,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
throw new InvalidTargetAttributeException();
}
final JpaTarget target = targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
final JpaTarget target = targetRepository.getByControllerId(controllerId);
// get the modifiable attribute map
final Map<String, String> controllerAttributes = target.getControllerAttributes();
@@ -447,7 +446,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Override
public Optional<Target> getByControllerId(final String controllerId) {
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId)).map(Target.class::cast);
return targetRepository.findByControllerId(controllerId).map(Target.class::cast);
}
@Override
@@ -541,20 +540,16 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Override
public void deleteExistingTarget(@NotEmpty final String controllerId) {
final Target target = targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
targetRepository.deleteById(target.getId());
targetRepository.deleteById(targetRepository.getByControllerId(controllerId).getId());
}
@Override
public Optional<Action> getInstalledActionByTarget(final String controllerId) {
final JpaTarget jpaTarget = targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
final JpaDistributionSet installedDistributionSet = jpaTarget.getInstalledDistributionSet();
if (null != installedDistributionSet) {
return actionRepository.findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(jpaTarget.getId(),
installedDistributionSet.getId(), FINISHED);
final JpaDistributionSet installedDistributionSet = targetRepository.getByControllerId(controllerId).getInstalledDistributionSet();
if (installedDistributionSet != null) {
final JpaTarget jpaTarget = targetRepository.getByControllerId(controllerId);
return actionRepository.findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(
jpaTarget.getId(), installedDistributionSet.getId(), FINISHED);
} else {
return Optional.empty();
}

View File

@@ -486,16 +486,12 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
return targetRepository
.findOne(TargetSpecifications.hasControllerId(controllerId))
.map(JpaTarget::getAssignedDistributionSet);
return targetRepository.findByControllerId(controllerId).map(JpaTarget::getAssignedDistributionSet);
}
@Override
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
return targetRepository
.findOne(TargetSpecifications.hasControllerId(controllerId))
.map(JpaTarget::getInstalledDistributionSet);
return targetRepository.findByControllerId(controllerId).map(JpaTarget::getInstalledDistributionSet);
}
@Override
@@ -710,8 +706,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
}
private void checkCompatibilityForMultiDsAssignment(final String controllerId, final List<Long> distSetIds) {
final Target target = targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
final Target target = targetRepository.getByControllerId(controllerId);
if (target.getTargetType() != null) {
// we assume that list of assigned DS is less than

View File

@@ -73,8 +73,10 @@ import org.springframework.validation.annotation.Validated;
public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement {
private static final int MAX_TENANTS_QUERY = 1000;
private final String countArtifactQuery;
private final String countSoftwareModulesQuery;
@Autowired
private EntityManager entityManager;
@Autowired
@@ -284,12 +286,6 @@ 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();
}

View File

@@ -410,7 +410,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public Optional<Target> getByControllerID(final String controllerId) {
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId)).map(Target.class::cast);
return targetRepository.findByControllerId(controllerId).map(Target.class::cast);
}
@Override
@@ -892,8 +892,7 @@ public class JpaTargetManagement implements TargetManagement {
}
private JpaTarget getByControllerIdAndThrowIfNotFound(final String controllerId) {
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
return targetRepository.getByControllerId(controllerId);
}
private JpaTargetType getTargetTypeByIdAndThrowIfNotFound(final long id) {
@@ -960,7 +959,7 @@ public class JpaTargetManagement implements TargetManagement {
final JpaTargetTag tag = targetTagRepository.findById(targetTagId)
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId));
final List<JpaTarget> targets = controllerIds.size() == 1 ?
targetRepository.findOne(TargetSpecifications.hasControllerId(controllerIds.iterator().next()))
targetRepository.findByControllerId(controllerIds.iterator().next())
.map(List::of)
.orElseGet(Collections::emptyList) :
targetRepository

View File

@@ -24,11 +24,9 @@ import lombok.Setter;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
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.

View File

@@ -37,15 +37,13 @@ import org.springframework.transaction.annotation.Transactional;
@NoRepositoryBean
@Transactional(readOnly = true)
public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity>
extends PagingAndSortingRepository<T, Long>, CrudRepository<T, Long>, JpaSpecificationExecutor<T>,
NoCountSliceRepository<T>, ACMRepository<T> {
extends PagingAndSortingRepository<T, Long>, CrudRepository<T, Long>, JpaSpecificationExecutor<T>, NoCountSliceRepository<T>,
ACMRepository<T> {
/**
* Overrides
* {@link org.springframework.data.repository.CrudRepository#saveAll(Iterable)}
* to return a list of created entities instead of an instance of
* {@link Iterable} to be able to work with it directly in further code
* processing instead of converting the {@link Iterable}.
* Overrides {@link org.springframework.data.repository.CrudRepository#saveAll(Iterable)} to return a list of created entities instead
* of an instance of {@link Iterable} to be able to work with it directly in further code processing instead of converting the
* {@link Iterable}.
*
* @param entities to persist in the database
* @return the created entities
@@ -55,11 +53,9 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
<S extends T> List<S> saveAll(Iterable<S> entities);
/**
* Overrides
* {@link org.springframework.data.repository.CrudRepository#findAll()}
* to return a list of found entities instead of an instance of
* {@link Iterable} to be able to work with it directly in further code
* processing instead of converting the {@link Iterable}.
* Overrides {@link org.springframework.data.repository.CrudRepository#findAll()} to return a list of found entities instead of
* an instance of {@link Iterable} to be able to work with it directly in further code processing instead of converting the
* {@link Iterable}.
*
* @return the found entities
*/
@@ -67,22 +63,9 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
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)}
* to return a list of found entities instead of an instance of
* {@link Iterable} to be able to work with it directly in further code
* processing instead of converting the {@link Iterable}.
* Overrides {@link org.springframework.data.repository.CrudRepository#findAllById(Iterable)} to return a list of found entities instead
* of an instance of {@link Iterable} to be able to work with it directly in further code processing instead of converting the
* {@link Iterable}.
*
* @param ids to search in the database for
* @return the found entities
@@ -92,10 +75,8 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
// TODO To be considered if this method is needed at all
/**
* Deletes all entities of a given tenant from this repository. For safety
* reasons (this is a "delete everything" query after all) we add the tenant
* manually to query even if this will be done by {@link EntityManager}
* anyhow. The DB should take care of optimizing this away.
* Deletes all entities of a given tenant from this repository. For safety reasons (this is a "delete everything" query after all) we add
* the tenant manually to query even if this will be done by {@link EntityManager} anyhow. The DB should take care of optimizing this away.
* <p/>
*
* @param tenant to delete data from
@@ -103,11 +84,9 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
void deleteByTenant(String tenant);
/**
* Returns a wrapper (or the same instance if access controller is <code>null</code> of this repository that
* supports ACM.
* Returns a wrapper (or the same instance if access controller is <code>null</code> of this repository that supports ACM.
* <p/>
* Note: To use ACM support the returned object shall be used! <code>this</code> object will not achieve ACM
* support!
* Note: To use ACM support the returned object shall be used! <code>this</code> object will not achieve ACM support!
* <p/>
* Notes on ACM support (if enabled, i.e. <code>accessController</code> is not <code>null</code>):
* <ul>
@@ -123,7 +102,6 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
* </ul>
*
* @param accessController access controller to be applied to the result
* @param entityType the entity type of the repository
* @return a repository that supports ACM.
*/
default BaseEntityRepository<T> withACM(@Nullable final AccessController<T> accessController) {
@@ -152,4 +130,4 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
default Optional<AccessController<T>> getAccessController() {
return Optional.empty();
}
}
}

View File

@@ -322,7 +322,11 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
.filter(value -> repository.getDomainClass().isAssignableFrom(value.getClass()))
.isPresent()) {
return ((Optional<T>) result).filter(
t -> isOperationAllowed(AccessController.Operation.READ, t, accessController));
t -> {
// if not accessible - throws exception (as for iterables or single entities)
accessController.assertOperationAllowed(AccessController.Operation.READ, t);
return true;
});
} else if (repository.getDomainClass().isAssignableFrom(method.getReturnType())) {
accessController.assertOperationAllowed(AccessController.Operation.READ, (T) result);
}

View File

@@ -10,11 +10,14 @@
package org.eclipse.hawkbit.repository.jpa.repository;
import java.util.Collection;
import java.util.Optional;
import jakarta.persistence.EntityManager;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
@@ -29,6 +32,15 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional(readOnly = true)
public interface TargetRepository extends BaseEntityRepository<JpaTarget> {
default Optional<JpaTarget> findByControllerId(final String controllerId) {
return findOne(TargetSpecifications.hasControllerId(controllerId));
}
default JpaTarget getByControllerId(final String controllerId) {
return findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
}
// TODO AC - remove it and use specification
/**