Add getting tenant with details (#2195)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-01-14 09:32:16 +02:00
committed by GitHub
parent b294798ae5
commit 626d4cc537
17 changed files with 162 additions and 112 deletions

View File

@@ -77,14 +77,14 @@ public class JpaActionManagement {
return handleAddUpdateActionStatus(actionStatus, action);
}
log.debug("Update of actionStatus {} for action {} not possible since action not active anymore.",
log.debug(
"Update of actionStatus {} for action {} not possible since action not active anymore.",
actionStatus.getStatus(), action.getId());
return action;
}
protected JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) {
return actionRepository.findById(actionId)
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
return actionRepository.findById(actionId).orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
}
protected void onActionStatusUpdate(final JpaActionStatus newActionStatus, final JpaAction action) {

View File

@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
import org.eclipse.hawkbit.repository.jpa.model.JpaAutoConfirmationStatus;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
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;
@@ -84,7 +85,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 = targetRepository.getByControllerId(controllerId);
final JpaTarget target = targetRepository.getWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_AUTO_CONFIRMATION_STATUS);
if (target.getAutoConfirmationStatus() != null) {
log.debug("'activateAutoConfirmation' was called for an controller id {} with active auto confirmation.", controllerId);
throw new AutoConfirmationAlreadyActiveException(controllerId);
@@ -109,18 +110,20 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
@Override
public Optional<AutoConfirmationStatus> getStatus(final String controllerId) {
return Optional.of(targetRepository.getByControllerId(controllerId)).map(JpaTarget::getAutoConfirmationStatus);
return Optional.of(targetRepository.getWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_AUTO_CONFIRMATION_STATUS))
.map(JpaTarget::getAutoConfirmationStatus);
}
@Override
@Transactional
public List<Action> autoConfirmActiveActions(final String controllerId) {
final JpaTarget target = targetRepository.getByControllerId(controllerId);
final JpaTarget target = targetRepository.getWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_AUTO_CONFIRMATION_STATUS);
if (target.getAutoConfirmationStatus() == null) {
// auto-confirmation is not active
return Collections.emptyList();
} else {
return giveConfirmationForActiveActions(target.getAutoConfirmationStatus());
}
return giveConfirmationForActiveActions(target.getAutoConfirmationStatus());
}
@Override

View File

@@ -62,6 +62,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
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;
@@ -494,12 +495,12 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
return targetRepository.findByControllerId(controllerId).map(JpaTarget::getAssignedDistributionSet);
return targetRepository.findWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_ASSIGNED_DISTRIBUTION_SET).map(JpaTarget::getAssignedDistributionSet);
}
@Override
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
return targetRepository.findByControllerId(controllerId).map(JpaTarget::getInstalledDistributionSet);
return targetRepository.findWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_INSTALLED_DISTRIBUTION_SET).map(JpaTarget::getInstalledDistributionSet);
}
@Override

View File

@@ -192,15 +192,12 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
return null;
}));
} while ((query = tenants.nextPageable()) != Pageable.unpaged());
}
@Override
public SystemUsageReportWithTenants getSystemUsageStatisticsWithTenants() {
final SystemUsageReportWithTenants result = (SystemUsageReportWithTenants) getSystemUsageStatistics();
usageStatsPerTenant(result);
return result;
}
@@ -213,19 +210,11 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
sumOfArtifacts = count.longValue();
}
// we use native queries to punch through the tenant boundaries. This
// has to be used with care!
final long targets = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_target")
.getSingleResult()).longValue();
final long artifacts = ((Number) entityManager.createNativeQuery(countArtifactQuery).getSingleResult())
.longValue();
final long actions = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_action")
.getSingleResult()).longValue();
return new SystemUsageReportWithTenants(targets, artifacts, actions, sumOfArtifacts,
tenantMetaDataRepository.count());
// we use native queries to punch through the tenant boundaries. This has to be used with care!
final long targets = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_target").getSingleResult()).longValue();
final long artifacts = ((Number) entityManager.createNativeQuery(countArtifactQuery).getSingleResult()).longValue();
final long actions = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_action").getSingleResult()).longValue();
return new SystemUsageReportWithTenants(targets, artifacts, actions, sumOfArtifacts, tenantMetaDataRepository.count());
}
@Override

View File

@@ -409,6 +409,11 @@ public class JpaTargetManagement implements TargetManagement {
return targetRepository.findByControllerId(controllerId).map(Target.class::cast);
}
@Override
public Target getWithDetails(final String controllerId, final String detailsKey) {
return targetRepository.getWithDetailsByControllerId(controllerId, "Target." + detailsKey);
}
@Override
public Slice<Target> findByFilters(final Pageable pageable, final FilterParams filterParams) {
final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams);
@@ -719,8 +724,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public Set<TargetTag> getTagsByControllerId(@NotEmpty String controllerId) {
// the method has PreAuthorized by itself
return getByControllerID(controllerId).map(JpaTarget.class::cast).map(JpaTarget::getTags)
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
return ((JpaTarget)getWithTags(controllerId)).getTags();
}
@Override

View File

@@ -65,13 +65,13 @@ import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
@Index(name = "sp_idx_action_prim", columnList = "tenant,id")
})
@NamedEntityGraphs({
@NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }),
@NamedEntityGraph(name = "Action.all", attributeNodes = {
@NamedAttributeNode(value = "target", subgraph = "target.ds"),
@NamedAttributeNode("distributionSet") },
subgraphs = @NamedSubgraph(
name = "target.ds",
attributeNodes = @NamedAttributeNode("assignedDistributionSet")))
attributeNodes = @NamedAttributeNode("assignedDistributionSet"))),
@NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") })
})
@Entity
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for sub entities

View File

@@ -34,6 +34,10 @@ import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapKeyColumn;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.NamedEntityGraphs;
import jakarta.persistence.NamedSubgraph;
import jakarta.persistence.OneToMany;
import jakarta.persistence.PrimaryKeyJoinColumn;
import jakarta.persistence.Table;
@@ -69,6 +73,7 @@ import org.springframework.util.ObjectUtils;
* JPA implementation of {@link Target}.
*/
@NoArgsConstructor // Default constructor for JPA
@Slf4j
@Entity
@Table(name = "sp_target",
indexes = {
@@ -78,9 +83,23 @@ import org.springframework.util.ObjectUtils;
@Index(name = "sp_idx_target_05", columnList = "tenant,last_modified_at"),
@Index(name = "sp_idx_target_prim", columnList = "tenant,id") },
uniqueConstraints = @UniqueConstraint(columnNames = { "controller_id", "tenant" }, name = "uk_tenant_controller_id"))
@NamedEntityGraphs({
@NamedEntityGraph(name = "Target.details", attributeNodes = {
@NamedAttributeNode("targetType"),
@NamedAttributeNode("installedDistributionSet"),
@NamedAttributeNode("assignedDistributionSet") }),
@NamedEntityGraph(name = "Target.targetType", attributeNodes = { @NamedAttributeNode("targetType") }),
@NamedEntityGraph(name = "Target.installedDistributionSet", attributeNodes = { @NamedAttributeNode("installedDistributionSet") },
subgraphs = { @NamedSubgraph(
name = "installedDistributionSet.optLockRevision",
attributeNodes = @NamedAttributeNode("optLockRevision")) }),
@NamedEntityGraph(name = "Target.assignedDistributionSet", attributeNodes = { @NamedAttributeNode("assignedDistributionSet") }),
@NamedEntityGraph(name = "Target.autoConfirmationStatus", attributeNodes = { @NamedAttributeNode("autoConfirmationStatus") }),
@NamedEntityGraph(name = "Target.tags", attributeNodes = { @NamedAttributeNode("tags") }),
@NamedEntityGraph(name = "Target.actions", attributeNodes = { @NamedAttributeNode("actions") }),
})
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for sub entities
@SuppressWarnings("squid:S2160")
@Slf4j
public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAwareEntity {
@Serial
@@ -281,10 +300,6 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
actions.add((JpaAction) action);
}
public List<Action> getActions() {
return actions == null ? Collections.emptyList() : Collections.unmodifiableList(actions);
}
@Override
public void fireCreateEvent() {
EventPublisherHolder.getInstance().getEventPublisher()

View File

@@ -10,20 +10,19 @@
package org.eclipse.hawkbit.repository.jpa.repository;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.Query;
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;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
@@ -46,15 +45,18 @@ public class HawkbitBaseRepository<T, ID extends Serializable> extends SimpleJpa
implements JpaSpecificationEntityGraphExecutor<T>, NoCountSliceRepository<T>, ACMRepository<T> {
private final EntityManager entityManager;
private final Logger log;
public HawkbitBaseRepository(final Class<T> domainClass, final EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
log = LoggerFactory.getLogger(getDomainClass());
}
public HawkbitBaseRepository(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
log = LoggerFactory.getLogger(getDomainClass());
}
@Override
@@ -149,8 +151,17 @@ public class HawkbitBaseRepository<T, ID extends Serializable> extends SimpleJpa
}
private TypedQuery<T> withEntityGraph(final TypedQuery<T> query, final String entityGraph) {
final EntityGraph<?> graph = ObjectUtils.isEmpty(entityGraph) ? null : entityManager.createEntityGraph(entityGraph);
return graph == null ? query : query.setHint("jakarta.persistence.loadgraph", graph);
if (ObjectUtils.isEmpty(entityGraph)) {
return query;
} else {
final EntityGraph<?> graph = entityManager.createEntityGraph(entityGraph);
if (graph == null) {
log.warn("Entity graph {} not found", entityGraph);
return query;
} else {
return query.setHint("jakarta.persistence.loadgraph", graph);
}
}
}
private <S extends T> Page<S> readPageWithoutCount(final TypedQuery<S> query, final Pageable pageable) {

View File

@@ -35,10 +35,14 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget> {
default Optional<JpaTarget> findByControllerId(final String controllerId) {
return findOne(TargetSpecifications.hasControllerId(controllerId));
}
default Optional<JpaTarget> findWithDetailsByControllerId(final String controllerId, final String entityGraph) {
return findOne(TargetSpecifications.hasControllerId(controllerId), entityGraph);
}
default JpaTarget getByControllerId(final String controllerId) {
return findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
return findByControllerId(controllerId).orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
}
default JpaTarget getWithDetailsByControllerId(final String controllerId, final String entityGraph) {
return findWithDetailsByControllerId(controllerId, entityGraph).orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
}
// TODO AC - remove it and use specification