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

@@ -38,10 +38,10 @@ class DdiArtifactHashTest {
final String sha1Hash = "11111";
final String md5Hash = "22222";
final String sha256Hash = "33333";
final DdiArtifactHash DdiArtifact = new DdiArtifactHash(sha1Hash, md5Hash, sha256Hash);
final DdiArtifactHash ddiArtifact = new DdiArtifactHash(sha1Hash, md5Hash, sha256Hash);
// Test
final String serializedDdiArtifact = OBJECT_MAPPER.writeValueAsString(DdiArtifact);
final String serializedDdiArtifact = OBJECT_MAPPER.writeValueAsString(ddiArtifact);
final DdiArtifactHash deserializedDdiArtifact = OBJECT_MAPPER.readValue(serializedDdiArtifact, DdiArtifactHash.class);
assertThat(serializedDdiArtifact).contains(sha1Hash, md5Hash, sha256Hash);
assertThat(deserializedDdiArtifact.getSha1()).isEqualTo(sha1Hash);

View File

@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.ddi.rest.resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

View File

@@ -341,7 +341,7 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest {
final DdiActivateAutoConfirmation body = new DdiActivateAutoConfirmation(initiator, remark);
mvc.perform(post(ACTIVATE_AUTO_CONFIRM, tenantAware.getCurrentTenant(), controllerId)
.content(getMapper().writeValueAsString(body)).contentType(MediaType.APPLICATION_JSON_UTF8))
.content(getMapper().writeValueAsString(body)).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());

View File

@@ -626,6 +626,7 @@ public class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest {
.andExpect(status().isNotAcceptable());
}
@SuppressWarnings("java:S1144") // java:S1144 - used in MethodSource, sonar my find it incorrectly as unused
private static Stream<Action.ActionType> actionTypeForDeployment() {
return Stream.of(Action.ActionType.SOFT, Action.ActionType.FORCED);
}

View File

@@ -62,10 +62,9 @@ class BaseAmqpServiceTest {
@Description("Tests invalid null message content")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) })
void convertMessageWithNullContent() {
final Message message = createMessage("".getBytes());
assertThatExceptionOfType(MessageConversionException.class)
.as("Expected MessageConversionException for invalid JSON")
.isThrownBy(() -> baseAmqpService.convertMessage(message, DmfActionUpdateStatus.class));
assertThatExceptionOfType(IllegalArgumentException.class)
.as("Expected IllegalArgumentException for invalid (null) JSON")
.isThrownBy(() -> createMessage(null));
}
@Test
@@ -74,7 +73,7 @@ class BaseAmqpServiceTest {
void updateActionStatusWithEmptyContent() {
final Message message = createMessage("".getBytes());
assertThatExceptionOfType(MessageConversionException.class)
.as("Expected MessageConversionException for invalid JSON")
.as("Expected MessageConversionException for invalid (empty) JSON")
.isThrownBy(() -> baseAmqpService.convertMessage(message, DmfActionUpdateStatus.class));
}

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;
});
}
}
}

View File

@@ -47,6 +47,7 @@ public class Amqp {
return vHosts.computeIfAbsent(vHost, vh -> new VHost(getConnectionFactory(dmf, vHost), amqpProperties, initVHost));
}
@SuppressWarnings("java:S4449") // java:S4449 - setUsername/Password is called with non-null
private ConnectionFactory getConnectionFactory(final DMF dmf, final String vHost) {
final CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(rabbitProperties.getHost());

View File

@@ -9,6 +9,9 @@
*/
package org.eclipse.hawkbit.ui.simple.view;
// java:S1214 - implementations of Constants interface extends other classes, so if make this class we shall go for static imports
// which is not not better
@SuppressWarnings("java:S1214")
public interface Constants {
// properties