Skip to content

Commit

Permalink
Add getting tenant with details (#2195)
Browse files Browse the repository at this point in the history
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
  • Loading branch information
avgustinmm authored Jan 14, 2025
1 parent b294798 commit 626d4cc
Show file tree
Hide file tree
Showing 17 changed files with 162 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -994,9 +994,9 @@ void verifyDownloadAndInstallDirectlySendOnAutoConfirmationEnabled() {

registerAndAssertTargetWithExistingTenant(controllerId);

assertThat(targetManagement.getByControllerID(controllerId).map(Target::getAutoConfirmationStatus)).isEmpty();
assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNull();
confirmationManagement.activateAutoConfirmation(controllerId, null, null);
assertThat(targetManagement.getByControllerID(controllerId).map(Target::getAutoConfirmationStatus)).isPresent();
assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNotNull();

final DistributionSetAssignmentResult assignmentResult = prepareDistributionSetAndAssign(controllerId);
final Long actionId = getFirstAssignedActionId(assignmentResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ static List<MgmtAction> toResponse(final String targetId, final Collection<Actio
return Collections.emptyList();
}

return actions.stream().map(action -> toResponse(targetId, action)).collect(Collectors.toList());
return actions.stream().map(action -> toResponse(targetId, action)).toList();
}

static MgmtMetadata toResponseTargetMetadata(final TargetMetadata metadata) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ public ResponseEntity<List<MgmtMetadata>> createMetadata(final String targetId,

@Override
public ResponseEntity<MgmtTargetAutoConfirm> getAutoConfirmStatus(final String targetId) {
final Target findTarget = findTargetWithExceptionIfNotFound(targetId);
final Target findTarget = targetManagement.getWithAutoConfigurationStatus(targetId);
final MgmtTargetAutoConfirm state = MgmtTargetMapper.getTargetAutoConfirmResponse(findTarget);
return ResponseEntity.ok(state);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
*/
public interface TargetManagement {

String DETAILS_BASE = "base";
String DETAILS_AUTO_CONFIRMATION_STATUS = "autoConfirmationStatus";
String DETAILS_TAGS = "tags";
String DETAILS_ACTIONS = "actions";

/**
* Counts number of targets with the given distribution set assigned.
*
Expand Down Expand Up @@ -221,8 +226,8 @@ public interface TargetManagement {
* @throws EntityNotFoundException if distribution set with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(@NotNull Pageable pageRequest,
long distributionSetId, @NotNull String rsqlParam);
Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(
@NotNull Pageable pageRequest, long distributionSetId, @NotNull String rsqlParam);

/**
* Counts all targets for all the given parameter {@link TargetFilterQuery} and
Expand Down Expand Up @@ -361,6 +366,37 @@ Page<Target> findByAssignedDistributionSetAndRsql(@NotNull Pageable pageReq, lon
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Optional<Target> getByControllerID(@NotEmpty String controllerId);


/**
* Gets a {@link Target} based a given controller id and includes the details specified by the details key.
*
* @param controllerId to look for.
* @param detailsKey the key of the details to include, e.g. {@link #DETAILS_AUTO_CONFIRMATION_STATUS}
* @return {@link Target}
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Target getWithDetails(@NotEmpty String controllerId, String detailsKey);

@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
default Target getWithDetails(@NotEmpty String controllerId) {
return getWithDetails(controllerId, DETAILS_BASE);
}

@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
default Target getWithAutoConfigurationStatus(@NotEmpty String controllerId) {
return getWithDetails(controllerId, DETAILS_AUTO_CONFIRMATION_STATUS);
}

@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
default Target getWithTags(@NotEmpty String controllerId) {
return getWithDetails(controllerId, DETAILS_TAGS);
}

@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
default Target getWithActions(@NotEmpty String controllerId) {
return getWithDetails(controllerId, DETAILS_ACTIONS);
}

/**
* Filter {@link Target}s for all the given parameters. If all parameters except
* pageable are null, all available {@link Target}s are returned.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ protected Action addActionStatus(final JpaActionStatusCreate statusCreate) {
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
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;
Expand Down Expand Up @@ -84,7 +85,7 @@ public List<Action> findActiveActionsWaitingConfirmation(final String controller
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);
Expand All @@ -109,18 +110,20 @@ public AutoConfirmationStatus activateAutoConfirmation(final String controllerId

@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
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;
Expand Down Expand Up @@ -494,12 +495,12 @@ public void startScheduledActions(final List<Action> rolloutGroupActions) {

@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,12 @@ public void forEachTenant(final Consumer<String> consumer) {
return null;
}));
} while ((query = tenants.nextPageable()) != Pageable.unpaged());

}

@Override
public SystemUsageReportWithTenants getSystemUsageStatisticsWithTenants() {
final SystemUsageReportWithTenants result = (SystemUsageReportWithTenants) getSystemUsageStatistics();

usageStatsPerTenant(result);

return result;
}

Expand All @@ -213,19 +210,11 @@ public SystemUsageReport getSystemUsageStatistics() {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,11 @@ public Optional<Target> getByControllerID(final String controllerId) {
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);
Expand Down Expand Up @@ -719,8 +724,7 @@ public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(fi
@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@
@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
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;
Expand Down Expand Up @@ -69,6 +73,7 @@
* JPA implementation of {@link Target}.
*/
@NoArgsConstructor // Default constructor for JPA
@Slf4j
@Entity
@Table(name = "sp_target",
indexes = {
Expand All @@ -78,9 +83,23 @@
@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
Expand Down Expand Up @@ -281,10 +300,6 @@ public void addAction(final Action action) {
actions.add((JpaAction) action);
}

public List<Action> getActions() {
return actions == null ? Collections.emptyList() : Collections.unmodifiableList(actions);
}

@Override
public void fireCreateEvent() {
EventPublisherHolder.getInstance().getEventPublisher()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -149,8 +151,17 @@ public String toString() {
}

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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 626d4cc

Please sign in to comment.