TargetManagement over RepositoryManagement (#2599)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-08-07 17:20:22 +03:00
committed by GitHub
parent 08ff739bbe
commit c038c507a9
62 changed files with 692 additions and 1563 deletions

View File

@@ -85,7 +85,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
private final DistributionSetTypeManagement<? extends DistributionSetType> distributionSetTypeManagement;
private final DistributionSetInvalidationManagement distributionSetInvalidationManagement;
private final TargetManagement targetManagement;
private final TargetManagement<? extends Target> targetManagement;
private final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement;
private final DeploymentManagement deployManagement;
private final SystemManagement systemManagement;
@@ -99,7 +99,8 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
final DistributionSetTypeManagement<? extends DistributionSetType> distributionSetTypeManagement,
final DistributionSetInvalidationManagement distributionSetInvalidationManagement,
final TargetManagement targetManagement, final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement,
final TargetManagement<? extends Target> targetManagement,
final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement,
final DeploymentManagement deployManagement, final TenantConfigurationManagement tenantConfigurationManagement,
final MgmtDistributionSetMapper mgmtDistributionSetMapper,
final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext) {
@@ -120,18 +121,15 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
public ResponseEntity<PagedList<MgmtDistributionSet>> getDistributionSets(
final String rsqlParam, final int pagingOffsetParam, final int pagingLimitParam, final String sortParam) {
final Pageable pageable = PagingUtility.toPageable(pagingOffsetParam, pagingLimitParam, sanitizeDistributionSetSortParam(sortParam));
final Slice<? extends DistributionSet> findDsPage;
final long countModulesAll;
final Page<? extends DistributionSet> findDsPage;
if (rsqlParam != null) {
findDsPage = distributionSetManagement.findByRsql(rsqlParam, pageable);
countModulesAll = ((Page<? extends DistributionSet>) findDsPage).getTotalElements();
} else {
findDsPage = distributionSetManagement.findAll(pageable);
countModulesAll = distributionSetManagement.count();
}
final List<MgmtDistributionSet> rest = MgmtDistributionSetMapper.toResponseFromDsList(findDsPage.getContent());
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
return ResponseEntity.ok(new PagedList<>(rest, findDsPage.getTotalElements()));
}
@Override
@@ -201,9 +199,9 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
final Pageable pageable = PagingUtility.toPageable(pagingOffsetParam, pagingLimitParam, sanitizeDistributionSetSortParam(sortParam));
final Page<Target> targetsAssignedDS;
if (rsqlParam != null) {
targetsAssignedDS = this.targetManagement.findByAssignedDistributionSetAndRsql(distributionSetId, rsqlParam, pageable);
targetsAssignedDS = targetManagement.findByAssignedDistributionSetAndRsql(distributionSetId, rsqlParam, pageable);
} else {
targetsAssignedDS = this.targetManagement.findByAssignedDistributionSet(distributionSetId, pageable);
targetsAssignedDS = targetManagement.findByAssignedDistributionSet(distributionSetId, pageable);
}
return ResponseEntity.ok(new PagedList<>(

View File

@@ -54,8 +54,8 @@ import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetMapper;
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException;
@@ -65,6 +65,7 @@ import org.eclipse.hawkbit.repository.model.DeploymentRequest;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.data.domain.Page;
@@ -83,25 +84,25 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
private static final String ACTION_TARGET_MISSING_ASSIGN_WARN = "given action ({}) is not assigned to given target ({}).";
private final TargetManagement targetManagement;
private final TargetManagement<? extends Target> targetManagement;
private final TargetTypeManagement<? extends TargetType> targetTypeManagement;
private final ConfirmationManagement confirmationManagement;
private final DeploymentManagement deploymentManagement;
private final MgmtTargetMapper mgmtTargetMapper;
private final MgmtDistributionSetMapper mgmtDistributionSetMapper;
private final EntityFactory entityFactory;
private final TenantConfigHelper tenantConfigHelper;
MgmtTargetResource(
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
final ConfirmationManagement confirmationManagement,
final MgmtDistributionSetMapper mgmtDistributionSetMapper,
final EntityFactory entityFactory,
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
final TargetManagement<? extends Target> targetManagement, final TargetTypeManagement<? extends TargetType> targetTypeManagement,
final DeploymentManagement deploymentManagement, final ConfirmationManagement confirmationManagement,
final MgmtTargetMapper mgmtTargetMapper, final MgmtDistributionSetMapper mgmtDistributionSetMapper,
final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement tenantConfigurationManagement) {
this.targetManagement = targetManagement;
this.targetTypeManagement = targetTypeManagement;
this.deploymentManagement = deploymentManagement;
this.confirmationManagement = confirmationManagement;
this.mgmtTargetMapper = mgmtTargetMapper;
this.mgmtDistributionSetMapper = mgmtDistributionSetMapper;
this.entityFactory = entityFactory;
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
}
@@ -119,24 +120,21 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
public ResponseEntity<PagedList<MgmtTarget>> getTargets(
final String rsqlParam, final int pagingOffsetParam, final int pagingLimitParam, final String sortParam) {
final Pageable pageable = PagingUtility.toPageable(pagingOffsetParam, pagingLimitParam, sanitizeTargetSortParam(sortParam));
final Slice<Target> findTargetsAll;
final long countTargetsAll;
final Page<? extends Target> findTargetsAll;
if (rsqlParam != null) {
findTargetsAll = targetManagement.findByRsql(rsqlParam, pageable);
countTargetsAll = targetManagement.countByRsql(rsqlParam);
} else {
findTargetsAll = targetManagement.findAll(pageable);
countTargetsAll = targetManagement.count();
}
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper);
return ResponseEntity.ok(new PagedList<>(rest, countTargetsAll));
return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements()));
}
@Override
public ResponseEntity<List<MgmtTarget>> createTargets(final List<MgmtTargetRequestBody> targets) {
log.debug("creating {} targets", targets.size());
final Collection<Target> createdTargets = this.targetManagement.create(MgmtTargetMapper.fromRequest(entityFactory, targets));
final Collection<? extends Target> createdTargets = this.targetManagement.create(mgmtTargetMapper.fromRequest(targets));
log.debug("{} targets created, return status {}", targets.size(), HttpStatus.CREATED);
return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets, tenantConfigHelper), HttpStatus.CREATED);
}
@@ -152,22 +150,26 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
}
}
final Target updateTarget;
if (targetRest.getTargetType() != null && targetRest.getTargetType() == -1L) {
// if targetType in request is -1 - unassign targetType from target
this.targetManagement.unassignType(targetId);
// update target without targetType here ...
updateTarget = this.targetManagement.update(entityFactory.target().update(targetId)
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
.securityToken(targetRest.getSecurityToken()).requestAttributes(targetRest.getRequestAttributes()));
} else {
updateTarget = this.targetManagement.update(
entityFactory.target().update(targetId).name(targetRest.getName()).description(targetRest.getDescription())
.address(targetRest.getAddress()).targetType(targetRest.getTargetType())
.securityToken(targetRest.getSecurityToken())
.requestAttributes(targetRest.getRequestAttributes()));
}
final Target targetToUpdate = targetManagement.getByControllerId(targetId)
.orElseThrow(() -> new EntityNotFoundException(Target.class, targetId));
final TargetType targetType = Optional.ofNullable(targetRest.getTargetType())
.map(targetTypeId -> {
if (targetTypeId == -1L) {
// if targetType in request is -1 - unassign targetType from target
targetManagement.unassignType(targetId);
return null;
} else {
return targetTypeManagement.get(targetRest.getTargetType())
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetRest.getTargetType()));
}
})
.orElse(null);
final Target updateTarget = targetManagement.update(TargetManagement.Update.builder().id(targetToUpdate.getId())
.targetType(targetType)
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
.securityToken(targetRest.getSecurityToken())
.requestControllerAttributes(targetRest.getRequestAttributes())
.build());
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget, tenantConfigHelper, null);
MgmtTargetMapper.addTargetLinks(response);
@@ -294,7 +296,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
log.debug("updateActionConfirmation with data [targetId={}, actionId={}]: {}", targetId, actionId, actionConfirmation);
return getValidatedAction(targetId, actionId)
.<ResponseEntity<Void>>map(action -> {
.<ResponseEntity<Void>> map(action -> {
try {
switch (actionConfirmation.getConfirmation()) {
case CONFIRMED:
@@ -471,7 +473,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
}
private Target findTargetWithExceptionIfNotFound(final String targetId) {
return targetManagement.getByControllerID(targetId)
return targetManagement.getByControllerId(targetId)
.orElseThrow(() -> new EntityNotFoundException(Target.class, targetId));
}

View File

@@ -51,11 +51,11 @@ import org.springframework.web.bind.annotation.RestController;
public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
private final TargetTagManagement<? extends TargetTag> tagManagement;
private final TargetManagement targetManagement;
private final TargetManagement<? extends Target> targetManagement;
private final TenantConfigHelper tenantConfigHelper;
MgmtTargetTagResource(
final TargetTagManagement<? extends TargetTag> tagManagement, final TargetManagement targetManagement,
final TargetTagManagement<? extends TargetTag> tagManagement, final TargetManagement<? extends Target> targetManagement,
final SystemSecurityContext securityContext, final TenantConfigurationManagement configurationManagement) {
this.tagManagement = tagManagement;
this.targetManagement = targetManagement;
@@ -172,7 +172,7 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
@AuditLog(entity = "TargetTag", type = AuditLog.Type.UPDATE, description = "Unassign Target From Target Tag")
public ResponseEntity<Void> unassignTarget(final Long targetTagId, final String controllerId) {
log.debug("Unassign target {} for target tag {}", controllerId, targetTagId);
this.targetManagement.unassignTag(List.of(controllerId), targetTagId);
targetManagement.unassignTag(List.of(controllerId), targetTagId);
return ResponseEntity.ok().build();
}
@@ -182,10 +182,10 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
final Long targetTagId, final OnNotFoundPolicy onNotFoundPolicy, final List<String> controllerIds) {
log.debug("Unassign {} targets for target tag {}", controllerIds.size(), targetTagId);
if (onNotFoundPolicy == OnNotFoundPolicy.FAIL) {
this.targetManagement.unassignTag(controllerIds, targetTagId);
targetManagement.unassignTag(controllerIds, targetTagId);
} else {
final AtomicReference<Collection<String>> notFound = new AtomicReference<>();
this.targetManagement.unassignTag(controllerIds, targetTagId, notFound::set);
targetManagement.unassignTag(controllerIds, targetTagId, notFound::set);
if (notFound.get() != null && onNotFoundPolicy == OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL) {
// has not found and ON_WHAT_FOUND_AND_FAIL
throw new EntityNotFoundException(Target.class, notFound.get());

View File

@@ -13,17 +13,18 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.ZoneId;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.MgmtPollStatus;
@@ -41,8 +42,9 @@ import org.eclipse.hawkbit.mgmt.rest.api.SortDirection;
import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.builder.TargetCreate;
import org.eclipse.hawkbit.repository.TargetManagement.Create;
import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.ActionStatus;
@@ -51,18 +53,27 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.rest.json.model.ResponseList;
import org.eclipse.hawkbit.util.IpUtil;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
/**
* A mapper which maps repository model to RESTful model representation and back.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
@Service
public final class MgmtTargetMapper {
private final TargetTypeManagement<? extends TargetType> targetTypeManagement;
MgmtTargetMapper(final TargetTypeManagement<? extends TargetType> targetTypeManagement) {
this.targetTypeManagement = targetTypeManagement;
}
/**
* Add links to a target response.
*
@@ -114,7 +125,7 @@ public final class MgmtTargetMapper {
* @param targets list of targets
* @return the response
*/
public static List<MgmtTarget> toResponse(final Collection<Target> targets, final TenantConfigHelper configHelper) {
public static List<MgmtTarget> toResponse(final Collection<? extends Target> targets, final TenantConfigHelper configHelper) {
if (targets == null) {
return Collections.emptyList();
}
@@ -142,12 +153,17 @@ public final class MgmtTargetMapper {
targetRest.setUpdateStatus(target.getUpdateStatus().name().toLowerCase());
targetRest.setGroup(target.getGroup());
final URI address = target.getAddress();
final String address = target.getAddress();
if (address != null) {
if (IpUtil.isIpAddresKnown(address)) {
targetRest.setIpAddress(address.getHost());
try {
final URI addressURI = new URI(address);
if (IpUtil.isIpAddresKnown(addressURI)) {
targetRest.setIpAddress(addressURI.getHost());
}
} catch (final URISyntaxException e) {
log.warn("Fail to parse address to URI: {}", e.getMessage());
}
targetRest.setAddress(address.toString());
targetRest.setAddress(address);
}
targetRest.setCreatedBy(target.getCreatedBy());
@@ -184,12 +200,12 @@ public final class MgmtTargetMapper {
return targetRest;
}
public static List<TargetCreate> fromRequest(final EntityFactory entityFactory, final Collection<MgmtTargetRequestBody> targetsRest) {
public List<Create> fromRequest(final Collection<MgmtTargetRequestBody> targetsRest) {
if (targetsRest == null) {
return Collections.emptyList();
}
return targetsRest.stream().map(targetRest -> fromRequest(entityFactory, targetRest)).toList();
return targetsRest.stream().map(this::fromRequest).toList();
}
public static Map<String, String> fromRequestMetadata(final List<MgmtMetadata> metadata) {
@@ -207,7 +223,7 @@ public final class MgmtTargetMapper {
return actionStatus.stream()
.map(status -> toResponse(status,
deploymentManagement.findMessagesByActionStatusId(
status.getId(), PageRequest.of(0, MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT))
status.getId(), PageRequest.of(0, MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT))
.getContent()))
.toList();
}
@@ -323,10 +339,18 @@ public final class MgmtTargetMapper {
}
}
private static TargetCreate fromRequest(final EntityFactory entityFactory, final MgmtTargetRequestBody targetRest) {
return entityFactory.target().create().controllerId(targetRest.getControllerId()).name(targetRest.getName())
private Create fromRequest(final MgmtTargetRequestBody targetRest) {
return Create.builder()
.controllerId(targetRest.getControllerId()).name(targetRest.getName())
.description(targetRest.getDescription()).securityToken(targetRest.getSecurityToken())
.address(targetRest.getAddress()).targetType(targetRest.getTargetType()).group(targetRest.getGroup());
.address(targetRest.getAddress())
.targetType(Optional.ofNullable(targetRest.getTargetType())
.map(targetTypeId -> targetTypeManagement.get(targetTypeId)
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId)))
.map(TargetType.class::cast)
.orElse(null))
.group(targetRest.getGroup())
.build();
}
private static String getType(final Action action) {