Sonar Fixes (9) (#2221)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-01-23 15:02:03 +02:00
committed by GitHub
parent 21b901a559
commit a0d149cc1d
12 changed files with 72 additions and 94 deletions

View File

@@ -12,32 +12,27 @@ 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;
/**
* 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
*
* @param <T>
* @param <S>
* @param <ID>
* 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> {
@Autowired
BaseRepositoryTypeProvider baseRepoProvider;
private final 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) {
public CustomBaseRepositoryFactoryBean(final Class<? extends T> repositoryInterface, final BaseRepositoryTypeProvider baseRepoProvider) {
super(repositoryInterface);
this.baseRepoProvider = baseRepoProvider;
}
@Override

View File

@@ -927,7 +927,7 @@ public class RepositoryApplicationConfiguration {
@ConditionalOnProperty(prefix = "hawkbit.rollout.scheduler", name = "enabled", matchIfMissing = true)
RolloutScheduler rolloutScheduler(final SystemManagement systemManagement,
final RolloutHandler rolloutHandler, final SystemSecurityContext systemSecurityContext) {
return new RolloutScheduler(systemManagement, rolloutHandler, systemSecurityContext);
return new RolloutScheduler(rolloutHandler, systemManagement, systemSecurityContext);
}
/**

View File

@@ -118,11 +118,11 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
}
}
default <T extends AbstractJpaTenantAwareBaseEntity> Specification<T> byIdSpec(final Long id) {
default <S extends AbstractJpaTenantAwareBaseEntity> Specification<S> byIdSpec(final Long id) {
return (root, query, cb) -> cb.equal(root.get(AbstractJpaBaseEntity_.id), id);
}
default <T extends AbstractJpaTenantAwareBaseEntity> Specification<T> byIdsSpec(final Iterable<Long> ids) {
default <S extends AbstractJpaTenantAwareBaseEntity> Specification<S> byIdsSpec(final Iterable<Long> ids) {
final Collection<Long> collection;
if (ids instanceof Collection<Long> idCollection) {
collection = idCollection;

View File

@@ -92,7 +92,8 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
@Override
public void deleteAllById(@NonNull final Iterable<? extends Long> ids) {
final Set<Long> idList = toSetDistinct(ids);
final Set<Long> idList = new HashSet<>();
ids.forEach(idList::add);
if (count(AccessController.Operation.DELETE, byIdsSpec(idList)) != idList.size()) {
throw new InsufficientPermissionException("Has at least one id that is not allowed for deletion!");
}
@@ -342,54 +343,51 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
repository.getClass().getInterfaces(),
(proxy, method, args) -> {
try {
try {
// TODO - cache mapping so to speed things
final Method delegateMethod =
BaseEntityRepositoryACM.class.getDeclaredMethod(method.getName(), method.getParameterTypes());
return delegateMethod.invoke(repositoryACM, args);
} catch (final NoSuchMethodException e) {
// call to repository itself
}
if (method.getName().startsWith("find") || method.getName().startsWith("get")) {
final Object result = method.invoke(repository, args);
// Iterable, List, Page, Slice
if (Iterable.class.isAssignableFrom(method.getReturnType())) {
for (final Object e : (Iterable<?>) result) {
if (repository.getDomainClass().isAssignableFrom(e.getClass())) {
accessController.assertOperationAllowed(AccessController.Operation.READ, (T) e);
}
}
} else if (Optional.class.isAssignableFrom(method.getReturnType()) && ((Optional<?>) result)
.filter(value -> repository.getDomainClass().isAssignableFrom(value.getClass()))
.isPresent()) {
return ((Optional<T>) result).filter(
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);
}
return result;
} else if ("toString".equals(method.getName()) && method.getParameterCount() == 0) {
return BaseEntityRepositoryACM.class.getSimpleName() +
"(repository: " + repository + ", accessController: " + accessController + ")";
} else {
return method.invoke(repository, args);
}
// try to call a BaseEntityRepositoryACM method if declared
// TODO - cache mapping so to speed things
final Method delegateMethod =
BaseEntityRepositoryACM.class.getDeclaredMethod(method.getName(), method.getParameterTypes());
return delegateMethod.invoke(repositoryACM, args);
} catch (final InvocationTargetException e) {
throw e.getCause() == null ? e : e.getCause();
} catch (final NoSuchMethodException nsme) {
// not found
try {
// call to call a repository method
if (method.getName().startsWith("find") || method.getName().startsWith("get")) {
final Object result = method.invoke(repository, args);
// Iterable, List, Page, Slice
if (Iterable.class.isAssignableFrom(method.getReturnType())) {
for (final Object e : (Iterable<?>) result) {
if (repository.getDomainClass().isAssignableFrom(e.getClass())) {
accessController.assertOperationAllowed(AccessController.Operation.READ, (T) e);
}
}
} else if (Optional.class.isAssignableFrom(method.getReturnType()) && ((Optional<?>) result)
.filter(value -> repository.getDomainClass().isAssignableFrom(value.getClass()))
.isPresent()) {
return ((Optional<T>) result).filter(
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);
}
return result;
} else if ("toString".equals(method.getName()) && method.getParameterCount() == 0) {
return BaseEntityRepositoryACM.class.getSimpleName() +
"(repository: " + repository + ", accessController: " + accessController + ")";
} else {
return method.invoke(repository, args);
}
} catch (final InvocationTargetException ite) {
throw ite.getCause() == null ? ite : ite.getCause();
}
}
});
log.info("Proxy created -> {}", acmProxy);
return acmProxy;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Set<Long> toSetDistinct(final Iterable<? extends Long> i) {
final Set<Long> set = new HashSet<>();
i.forEach(set::add);
return set;
}
}

View File

@@ -26,49 +26,31 @@ public class RolloutScheduler {
private static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.rollout.scheduler.fixedDelay:2000}";
private final SystemManagement systemManagement;
private final RolloutHandler rolloutHandler;
private final SystemSecurityContext systemSecurityContext;
/**
* Constructor.
*
* @param systemManagement to find all tenants
* @param rolloutHandler to run the rollout handler
* @param systemSecurityContext to run as system
*/
public RolloutScheduler(final SystemManagement systemManagement, final RolloutHandler rolloutHandler,
final SystemSecurityContext systemSecurityContext) {
public RolloutScheduler(
final RolloutHandler rolloutHandler, final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext) {
this.systemManagement = systemManagement;
this.rolloutHandler = rolloutHandler;
this.systemSecurityContext = systemSecurityContext;
}
/**
* Scheduler method called by the spring-async mechanism. Retrieves all
* tenants from the {@link SystemManagement#findTenants} and runs for each
* tenant the {@link RolloutHandler#handleAll()} in the
* {@link SystemSecurityContext}.
* Scheduler method called by the spring-async mechanism. Retrieves all tenants from the {@link SystemManagement#findTenants} and
* runs for each tenant the {@link RolloutHandler#handleAll()} in the {@link SystemSecurityContext}.
*/
@Scheduled(initialDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER)
public void runningRolloutScheduler() {
log.debug("rollout schedule checker has been triggered.");
// run this code in system code privileged to have the necessary
// permission to query and create entities.
// run this code in system code privileged to have the necessary permission to query and create entities.
systemSecurityContext.runAsSystem(() -> {
// workaround eclipselink that is currently not possible to
// execute a query without multi-tenancy if MultiTenant
// annotation is used.
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458. So
// iterate through all tenants and execute the rollout check for
// each tenant seperately.
// workaround eclipselink that is currently not possible to execute a query without multi-tenancy if MultiTenant
// annotation is used. https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458. So, iterate through all tenants and execute the rollout
// check for each tenant separately.
systemManagement.forEachTenant(tenant -> rolloutHandler.handleAll());
return null;
});
}
}
}