Feature target type entity (#1162)
* Added Target Type model Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added Target Type JPA model Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added Target Type repository model classes Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Removed the name entity from Target Type Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Refactored the Target Type models Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added the DB migration script and updated the Target Type models Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added target type in target Mapper Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Changed the target type ID to Long Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added MYSQL DB migration script and removed the deleted column for target type Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Updated the DB migration script for target table Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added manyToMany reltation between target type and Ds type Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added POSTGRESQL DB migration script Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added MSSQL SERVER DB migration script Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added DB2 DB migration script Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added missing license header and java docs Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added on delete cascade in DB migration script Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added Target Type specification Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Removed the delete cascade and Added type API Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * fixed API doc build Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added target type management test Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added target type events test Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added target type update and unassign to target Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added API tests for assigning target type to target Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added missing license header Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added missing docs Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Fixed sonar issues Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Fixed license header build issue Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Updated the attribute name to target type Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Fixed the review comments Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Removed unused error status variable Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added target API to assign target type Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Added the tests for assigning target type to target Signed-off-by: Anand kumar <anand.kumar@bosch-si.com> * Fixed the review comments for null check Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>
This commit is contained in:
@@ -32,6 +32,7 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
@@ -66,6 +67,8 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
private final Database database;
|
||||
@@ -74,12 +77,13 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
JpaDistributionSetTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
|
||||
final QuotaManagement quotaManagement) {
|
||||
this.distributionSetTypeRepository = distributionSetTypeRepository;
|
||||
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.targetTypeRepository = targetTypeRepository;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
this.database = database;
|
||||
this.quotaManagement = quotaManagement;
|
||||
@@ -190,7 +194,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the quota specifiying the maximum number of
|
||||
* Enforces the quota specifying the maximum number of
|
||||
* {@link SoftwareModuleType}s per {@link DistributionSetType}.
|
||||
*
|
||||
* @param id
|
||||
@@ -268,18 +272,28 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long typeId) {
|
||||
|
||||
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(typeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, typeId));
|
||||
|
||||
unassignDsTypeFromTargetTypes(typeId);
|
||||
|
||||
if (distributionSetRepository.countByTypeId(typeId) > 0) {
|
||||
toDelete.setDeleted(true);
|
||||
distributionSetTypeRepository.save(toDelete);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
distributionSetTypeRepository.deleteById(typeId);
|
||||
}
|
||||
}
|
||||
|
||||
private void unassignDsTypeFromTargetTypes(long typeId) {
|
||||
List<JpaTargetType> targetTypesByDsType = targetTypeRepository.findByDsType(typeId);
|
||||
targetTypesByDsType.forEach(targetType -> {
|
||||
targetType.removeDistributionSetType(typeId);
|
||||
targetTypeRepository.save(targetType);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TagBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeBuilder;
|
||||
@@ -42,6 +43,9 @@ public class JpaEntityFactory implements EntityFactory {
|
||||
@Autowired
|
||||
private DistributionSetBuilder distributionSetBuilder;
|
||||
|
||||
@Autowired
|
||||
private TargetBuilder targetBuilder;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetTypeBuilder distributionSetTypeBuilder;
|
||||
|
||||
@@ -57,6 +61,9 @@ public class JpaEntityFactory implements EntityFactory {
|
||||
@Autowired
|
||||
private SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder;
|
||||
|
||||
@Autowired
|
||||
private TargetTypeBuilder targetTypeBuilder;
|
||||
|
||||
@Override
|
||||
public MetaData generateDsMetadata(final String key, final String value) {
|
||||
return new JpaDistributionSetMetadata(key, StringUtils.trimWhitespace(value));
|
||||
@@ -79,7 +86,12 @@ public class JpaEntityFactory implements EntityFactory {
|
||||
|
||||
@Override
|
||||
public TargetBuilder target() {
|
||||
return new JpaTargetBuilder();
|
||||
return targetBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetTypeBuilder targetType() {
|
||||
return targetTypeBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
@@ -93,6 +94,9 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
@Autowired
|
||||
private TargetTagRepository targetTagRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetTypeRepository targetTypeRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetTagRepository distributionSetTagRepository;
|
||||
|
||||
@@ -255,6 +259,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
targetRepository.deleteByTenant(tenant);
|
||||
targetFilterQueryRepository.deleteByTenant(tenant);
|
||||
rolloutRepository.deleteByTenant(tenant);
|
||||
targetTypeRepository.deleteByTenant(tenant);
|
||||
targetTagRepository.deleteByTenant(tenant);
|
||||
distributionSetTagRepository.deleteByTenant(tenant);
|
||||
distributionSetRepository.deleteByTenant(tenant);
|
||||
|
||||
@@ -49,6 +49,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
@@ -63,6 +64,7 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
@@ -98,6 +100,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
private final TargetRepository targetRepository;
|
||||
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
|
||||
private final TargetMetadataRepository targetMetadataRepository;
|
||||
|
||||
private final RolloutGroupRepository rolloutGroupRepository;
|
||||
@@ -119,7 +123,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
private final Database database;
|
||||
|
||||
public JpaTargetManagement(final EntityManager entityManager, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||
final TargetRepository targetRepository, final TargetTypeRepository targetTypeRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
@@ -130,6 +134,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
this.entityManager = entityManager;
|
||||
this.quotaManagement = quotaManagement;
|
||||
this.targetRepository = targetRepository;
|
||||
this.targetTypeRepository = targetTypeRepository;
|
||||
this.targetMetadataRepository = targetMetadataRepository;
|
||||
this.rolloutGroupRepository = rolloutGroupRepository;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
@@ -152,6 +157,10 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
}
|
||||
|
||||
private JpaTargetType getTargetTypeByIdAndThrowIfNotFound(final long id) {
|
||||
return targetTypeRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(TargetType.class, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Target> getByControllerID(final Collection<String> controllerIDs) {
|
||||
return Collections.unmodifiableList(
|
||||
@@ -333,6 +342,10 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
update.getDescription().ifPresent(target::setDescription);
|
||||
update.getAddress().ifPresent(target::setAddress);
|
||||
update.getSecurityToken().ifPresent(target::setSecurityToken);
|
||||
if (update.getTargetTypeId() != null){
|
||||
TargetType targetType = getTargetTypeByIdAndThrowIfNotFound(update.getTargetTypeId());
|
||||
target.setTargetType(targetType);
|
||||
}
|
||||
|
||||
return targetRepository.save(target);
|
||||
}
|
||||
@@ -589,6 +602,24 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target unAssignType(final String controllerID) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerID);
|
||||
target.setTargetType(null);
|
||||
return targetRepository.save(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target assignType(String controllerID, long targetTypeId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerID);
|
||||
final JpaTargetType targetType = getTargetTypeByIdAndThrowIfNotFound(targetTypeId);
|
||||
target.setTargetType(targetType);
|
||||
return targetRepository.save(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByFilterOrderByLinkedDistributionSet(final Pageable pageable,
|
||||
final long orderByDistributionId, final FilterParams filterParams) {
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTargetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.TargetTypeInUseException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link TargetTypeManagement}.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
private final TargetRepository targetRepository;
|
||||
private final DistributionSetTypeRepository distributionSetTypeRepository;
|
||||
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
private final Database database;
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param targetTypeRepository
|
||||
* Target type repository
|
||||
* @param targetRepository
|
||||
* Target repository
|
||||
* @param virtualPropertyReplacer
|
||||
* replacer
|
||||
* @param database
|
||||
* database
|
||||
*/
|
||||
public JpaTargetTypeManagement(final TargetTypeRepository targetTypeRepository,
|
||||
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
|
||||
final QuotaManagement quotaManagement) {
|
||||
this.targetTypeRepository = targetTypeRepository;
|
||||
this.targetRepository = targetRepository;
|
||||
this.distributionSetTypeRepository = distributionSetTypeRepository;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
this.database = database;
|
||||
this.quotaManagement = quotaManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> getByName(String name) {
|
||||
return targetTypeRepository.findByName(name).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return targetTypeRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType create(TargetTypeCreate create) {
|
||||
final JpaTargetTypeCreate typeCreate = (JpaTargetTypeCreate) create;
|
||||
return targetTypeRepository.save(typeCreate.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetType> create(Collection<TargetTypeCreate> creates) {
|
||||
return creates.stream().map(this::create).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Long targetTypeId) {
|
||||
throwExceptionIfTargetTypeDoesNotExist(targetTypeId);
|
||||
|
||||
if (targetRepository.countByTargetTypeId(targetTypeId) > 0) {
|
||||
throw new TargetTypeInUseException("Cannot delete target type that is in use");
|
||||
}
|
||||
|
||||
targetTypeRepository.deleteById(targetTypeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<TargetType> findAll(Pageable pageable) {
|
||||
return convertPage(targetTypeRepository.findAll(pageable), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<TargetType> findByRsql(Pageable pageable, String rsqlParam) {
|
||||
final Specification<JpaTargetType> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, TargetTypeFields.class,
|
||||
virtualPropertyReplacer, database);
|
||||
|
||||
return convertPage(targetTypeRepository.findAll(spec, pageable), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> get(long id) {
|
||||
return targetTypeRepository.findById(id).map(targetType -> targetType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> findByTargetId(long targetId) {
|
||||
return targetTypeRepository
|
||||
.findOne(TargetTypeSpecification.hasTarget(targetId)).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetType> findByTargetIds(Collection<Long> targetIds) {
|
||||
return targetTypeRepository.findAll(TargetTypeSpecification.hasTarget(targetIds))
|
||||
.stream().map(TargetType.class::cast).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> findByTargetControllerId(String controllerId) {
|
||||
return targetTypeRepository
|
||||
.findOne(TargetTypeSpecification.hasTargetControllerId(controllerId)).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetType> findByTargetControllerIds(Collection<String> controllerIds) {
|
||||
return targetTypeRepository.findAll(TargetTypeSpecification.hasTargetControllerIdIn(controllerIds))
|
||||
.stream().map(TargetType.class::cast).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetType> get(Collection<Long> ids) {
|
||||
return Collections.unmodifiableList(targetTypeRepository.findAllById(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType update(TargetTypeUpdate update) {
|
||||
final GenericTargetTypeUpdate typeUpdate = (GenericTargetTypeUpdate) update;
|
||||
|
||||
final JpaTargetType type = findTargetTypeAndThrowExceptionIfNotFound(typeUpdate.getId());
|
||||
|
||||
typeUpdate.getName().ifPresent((type::setName));
|
||||
typeUpdate.getDescription().ifPresent(type::setDescription);
|
||||
typeUpdate.getColour().ifPresent(type::setColour);
|
||||
|
||||
return targetTypeRepository.save(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType assignCompatibleDistributionSetTypes(long targetTypeId, Collection<Long> distributionSetTypeIds) {
|
||||
final Collection<JpaDistributionSetType> dsTypes = distributionSetTypeRepository
|
||||
.findAllById(distributionSetTypeIds);
|
||||
|
||||
if (dsTypes.size() < distributionSetTypeIds.size()) {
|
||||
throw new EntityNotFoundException(DistributionSetType.class, distributionSetTypeIds,
|
||||
dsTypes.stream().map(DistributionSetType::getId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
final JpaTargetType type = findTargetTypeAndThrowExceptionIfNotFound(targetTypeId);
|
||||
assertDistributionSetTypeQuota(targetTypeId, distributionSetTypeIds.size());
|
||||
|
||||
dsTypes.forEach(type::addCompatibleDistributionSetType);
|
||||
|
||||
return targetTypeRepository.save(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType unassignDistributionSetType(long targetTypeId, long distributionSetTypeId) {
|
||||
final JpaTargetType type = findTargetTypeAndThrowExceptionIfNotFound(targetTypeId);
|
||||
findDsTypeAndThrowExceptionIfNotFound(distributionSetTypeId);
|
||||
type.removeDistributionSetType(distributionSetTypeId);
|
||||
|
||||
return targetTypeRepository.save(type);
|
||||
}
|
||||
|
||||
private JpaTargetType findTargetTypeAndThrowExceptionIfNotFound(final Long typeId) {
|
||||
return (JpaTargetType) get(typeId).orElseThrow(() -> new EntityNotFoundException(TargetType.class, typeId));
|
||||
}
|
||||
|
||||
private void findDsTypeAndThrowExceptionIfNotFound(final Long typeId) {
|
||||
distributionSetTypeRepository.findById(typeId).orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, typeId));
|
||||
}
|
||||
|
||||
private void throwExceptionIfTargetTypeDoesNotExist(final Long typeId) {
|
||||
if (!targetTypeRepository.existsById(typeId)) {
|
||||
throw new EntityNotFoundException(TargetType.class, typeId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the quota specifying the maximum number of
|
||||
* {@link DistributionSetType}s per {@link TargetType}.
|
||||
*
|
||||
* @param id
|
||||
* of the target type
|
||||
* @param requested
|
||||
* number of distribution set types to check
|
||||
*
|
||||
* @throws AssignmentQuotaExceededException
|
||||
* if the software module type quota is exceeded
|
||||
*/
|
||||
private void assertDistributionSetTypeQuota(final long id, final int requested) {
|
||||
QuotaHelper.assertAssignmentQuota(id, requested, quotaManagement.getMaxDistributionSetTypesPerTargetType(),
|
||||
DistributionSetType.class, TargetType.class, targetTypeRepository::countDsSetTypesById);
|
||||
}
|
||||
|
||||
private static Page<TargetType> convertPage(final Page<JpaTargetType> findAll, final Pageable pageable) {
|
||||
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
|
||||
}
|
||||
|
||||
private static Slice<TargetType> convertPage(final Slice<JpaTargetType> findAll, final Pageable pageable) {
|
||||
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
@@ -46,7 +47,9 @@ import org.eclipse.hawkbit.repository.builder.DistributionSetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
|
||||
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
|
||||
import org.eclipse.hawkbit.repository.event.remote.EventEntityManagerHolder;
|
||||
@@ -62,7 +65,9 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitDefaultServiceExecutor;
|
||||
@@ -85,6 +90,7 @@ import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||
@@ -231,6 +237,21 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
return new JpaDistributionSetBuilder(distributionSetTypeManagement, softwareManagement);
|
||||
}
|
||||
|
||||
@Bean
|
||||
TargetBuilder targetBuilder(final TargetTypeManagement targetTypeManagement){
|
||||
return new JpaTargetBuilder(targetTypeManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dsTypeManagement
|
||||
* for loading {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||
* @return TargetTypeBuilder bean
|
||||
*/
|
||||
@Bean
|
||||
TargetTypeBuilder targetTypeBuilder(final DistributionSetTypeManagement dsTypeManagement) {
|
||||
return new JpaTargetTypeBuilder(dsTypeManagement);
|
||||
}
|
||||
|
||||
@Bean
|
||||
SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder(
|
||||
final SoftwareModuleManagement softwareModuleManagement) {
|
||||
@@ -465,10 +486,26 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final TargetTypeRepository targetTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
|
||||
final QuotaManagement quotaManagement) {
|
||||
return new JpaDistributionSetTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
|
||||
distributionSetRepository, virtualPropertyReplacer, properties.getDatabase(), quotaManagement);
|
||||
distributionSetRepository, targetTypeRepository, virtualPropertyReplacer, properties.getDatabase(), quotaManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaTargetTypeManagement} bean.
|
||||
*
|
||||
* @return a new {@link TargetTypeManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TargetTypeManagement targetTypeManagement(final TargetTypeRepository targetTypeRepository,
|
||||
final TargetRepository targetRepository, final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
|
||||
final QuotaManagement quotaManagement) {
|
||||
return new JpaTargetTypeManagement(targetTypeRepository, targetRepository, distributionSetTypeRepository,
|
||||
virtualPropertyReplacer, properties.getDatabase(), quotaManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -504,11 +541,11 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final TargetTagRepository targetTagRepository, final EventPublisherHolder eventPublisherHolder,
|
||||
final TenantAware tenantAware, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
|
||||
return new JpaTargetManagement(entityManager, quotaManagement, targetRepository, targetMetadataRepository,
|
||||
return new JpaTargetManagement(entityManager, quotaManagement, targetRepository, targetTypeRepository, targetMetadataRepository,
|
||||
rolloutGroupRepository, distributionSetRepository, targetFilterQueryRepository, targetTagRepository,
|
||||
eventPublisherHolder, tenantAware, afterCommit, virtualPropertyReplacer, properties.getDatabase());
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -200,6 +201,15 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
||||
return this.count(Specification.where(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts {@link Target} instances of given type in the repository.
|
||||
*
|
||||
* @param targetTypeId
|
||||
* to search for
|
||||
* @return number of found {@link Target}s
|
||||
*/
|
||||
long countByTargetTypeId(Long targetTypeId);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* {@link PagingAndSortingRepository} for {@link JpaTargetType}.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetTypeRepository
|
||||
extends BaseEntityRepository<JpaTargetType, Long>, JpaSpecificationExecutor<JpaTargetType> {
|
||||
|
||||
/**
|
||||
* Finds {@link TargetType} in the repository matching an id.
|
||||
*
|
||||
* Calls version based on spec to allow injecting further specs
|
||||
*
|
||||
* @param id id to filter for
|
||||
* @return {@link Optional} of {@link TargetType}
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Optional<JpaTargetType> findById(@NonNull Long id) {
|
||||
return this.findOne(Specification.where(TargetTypeSpecification.hasId(id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ids
|
||||
* List of ID
|
||||
* @return Target type list
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default List<JpaTargetType> findAllById(Iterable<Long> ids) {
|
||||
final List<Long> collectedIds = StreamSupport.stream(ids.spliterator(), true).collect(Collectors.toList());
|
||||
return this.findAll(Specification.where(TargetTypeSpecification.hasIdIn(collectedIds)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the {@link TargetType}s with the given target IDs.
|
||||
*
|
||||
* @param targetTypeIDs
|
||||
* to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetType t WHERE t.id IN ?1")
|
||||
void deleteByIdIn(Collection<Long> targetTypeIDs);
|
||||
|
||||
/**
|
||||
* Finds all {@link TargetType}s in the repository.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @return {@link List} of {@link TargetType}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default List<JpaTargetType> findAll() {
|
||||
return this.findAll(Specification.where(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all {@link TargetType}s in the repository sorted.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @param sort instructions to sort result by
|
||||
* @return {@link List} of {@link TargetType}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Iterable<JpaTargetType> findAll(@NonNull Sort sort) {
|
||||
return this.findAll(Specification.where(null), sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a page of {@link TargetType}s in the repository.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @param pageable paging context
|
||||
* @return {@link List} of {@link TargetType}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Page<JpaTargetType> findAll(@NonNull Pageable pageable) {
|
||||
return this.findAll(Specification.where(null), pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether {@link TargetType} in the repository matching an id exists or not.
|
||||
*
|
||||
* Calls version based on spec to allow injecting further specs
|
||||
*
|
||||
* @param id id to check for
|
||||
* @return true if TargetType with id exists
|
||||
*/
|
||||
@Override
|
||||
default boolean existsById(@NonNull Long id) {
|
||||
return this.exists(TargetTypeSpecification.hasId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether {@link TargetType} in the repository matching a spec exists or not.
|
||||
*
|
||||
* @param spec to check for existence
|
||||
* @return true if target with id exists
|
||||
*/
|
||||
default boolean exists(@NonNull Specification<JpaTargetType> spec) {
|
||||
return this.count(spec) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count number of {@link TargetType}s in the repository.
|
||||
*
|
||||
* Calls version with an empty spec to allow injecting further specs
|
||||
*
|
||||
* @return number of targetTypes in the repository
|
||||
*/
|
||||
@Override
|
||||
default long count() {
|
||||
return this.count(Specification.where(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tenant
|
||||
* Tenant
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetType t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
@Query(value = "SELECT COUNT (t.id) FROM JpaDistributionSetType t JOIN t.compatibleToTargetTypes tt WHERE tt.id = :id")
|
||||
long countDsSetTypesById(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dsTypeId
|
||||
* to search for
|
||||
* @return all {@link TargetType}s in the repository with given
|
||||
* {@link TargetType#getName()}
|
||||
*/
|
||||
default List<JpaTargetType> findByDsType(@Param("id") Long dsTypeId) {
|
||||
return this.findAll(Specification.where(TargetTypeSpecification.hasDsSetType(dsTypeId)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* to search for
|
||||
* @return all {@link TargetType}s in the repository with given
|
||||
* {@link TargetType#getName()}
|
||||
*/
|
||||
default Optional<JpaTargetType> findByName(String name){
|
||||
return this.findOne(Specification.where(TargetTypeSpecification.hasName(name)));
|
||||
};
|
||||
}
|
||||
@@ -8,15 +8,26 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link Target}.
|
||||
*
|
||||
*/
|
||||
public class JpaTargetBuilder implements TargetBuilder {
|
||||
final private TargetTypeManagement targetTypeManagement;
|
||||
|
||||
/**
|
||||
* @param targetTypeManagement
|
||||
* Target type management
|
||||
*/
|
||||
public JpaTargetBuilder(TargetTypeManagement targetTypeManagement) {
|
||||
this.targetTypeManagement = targetTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetUpdate update(final String controllerId) {
|
||||
@@ -25,7 +36,7 @@ public class JpaTargetBuilder implements TargetBuilder {
|
||||
|
||||
@Override
|
||||
public TargetCreate create() {
|
||||
return new JpaTargetCreate();
|
||||
return new JpaTargetCreate(targetTypeManagement);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractTargetUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -20,8 +23,17 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> implements TargetCreate {
|
||||
|
||||
JpaTargetCreate() {
|
||||
private final TargetTypeManagement targetTypeManagement;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param targetTypeManagement
|
||||
* Target type management
|
||||
*/
|
||||
JpaTargetCreate(final TargetTypeManagement targetTypeManagement) {
|
||||
super(null);
|
||||
this.targetTypeManagement = targetTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,6 +50,12 @@ public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> im
|
||||
target.setName(name);
|
||||
}
|
||||
|
||||
if (targetTypeId != null){
|
||||
TargetType targetType = targetTypeManagement.get(targetTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId));
|
||||
target.setTargetType(targetType);
|
||||
}
|
||||
|
||||
target.setDescription(description);
|
||||
target.setAddress(address);
|
||||
target.setUpdateStatus(getStatus().orElse(TargetUpdateStatus.UNKNOWN));
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTargetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
|
||||
/**
|
||||
* Builder implementation for {@link TargetType}.
|
||||
*
|
||||
*/
|
||||
public class JpaTargetTypeBuilder implements TargetTypeBuilder {
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param distributionSetTypeManagement
|
||||
* Distribution set type management
|
||||
*/
|
||||
public JpaTargetTypeBuilder(DistributionSetTypeManagement distributionSetTypeManagement) {
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetTypeUpdate update(long id) {
|
||||
return new GenericTargetTypeUpdate(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetTypeCreate create() {
|
||||
return new JpaTargetTypeCreate(distributionSetTypeManagement);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractTargetTypeUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Create/build implementation.
|
||||
*
|
||||
*/
|
||||
public class JpaTargetTypeCreate extends AbstractTargetTypeUpdateCreate<TargetTypeCreate>
|
||||
implements TargetTypeCreate {
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param distributionSetTypeManagement
|
||||
* Distribution set type management
|
||||
*/
|
||||
JpaTargetTypeCreate(final DistributionSetTypeManagement distributionSetTypeManagement) {
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaTargetType build() {
|
||||
final JpaTargetType result = new JpaTargetType(name, description, colour);
|
||||
|
||||
findDistributionSetTypeWithExceptionIfNotFound(compatible).forEach(result::addCompatibleDistributionSetType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<DistributionSetType> findDistributionSetTypeWithExceptionIfNotFound(
|
||||
final Collection<Long> distributionSetTypeId) {
|
||||
if (CollectionUtils.isEmpty(distributionSetTypeId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Collection<DistributionSetType> type = distributionSetTypeManagement.get(distributionSetTypeId);
|
||||
if (type.size() < distributionSetTypeId.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModuleType.class, distributionSetTypeId);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,24 +8,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeUpdatedEvent;
|
||||
@@ -33,11 +15,30 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A distribution set type defines which software module types can or have to be
|
||||
* {@link DistributionSet}.
|
||||
@@ -72,6 +73,10 @@ public class JpaDistributionSetType extends AbstractJpaNamedEntity implements Di
|
||||
@Column(name = "deleted")
|
||||
private boolean deleted;
|
||||
|
||||
@CascadeOnDelete
|
||||
@ManyToMany(mappedBy = "distributionSetTypes", targetEntity = JpaTargetType.class, fetch = FetchType.LAZY)
|
||||
private List<TargetType> compatibleToTargetTypes;
|
||||
|
||||
public JpaDistributionSetType() {
|
||||
// default public constructor for JPA
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.eclipse.hawkbit.repository.model.PollStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||
@@ -162,6 +163,10 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
@JoinColumn(name = "target_id", nullable = false, updatable = false) }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
|
||||
private Map<String, String> controllerAttributes;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = true, targetEntity = JpaTargetType.class)
|
||||
@JoinColumn(name = "target_type", nullable = true, updatable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_relation_target_type"))
|
||||
private TargetType targetType;
|
||||
|
||||
// set default request controller attributes to true, because we want to
|
||||
// request them the first
|
||||
// time
|
||||
@@ -201,10 +206,16 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
: controllerId;
|
||||
}
|
||||
|
||||
JpaTarget() {
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public JpaTarget() {
|
||||
// empty constructor for JPA.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return assigned distribution set
|
||||
*/
|
||||
public DistributionSet getAssignedDistributionSet() {
|
||||
return assignedDistributionSet;
|
||||
}
|
||||
@@ -214,6 +225,9 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return controllerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tags
|
||||
*/
|
||||
public Set<TargetTag> getTags() {
|
||||
if (tags == null) {
|
||||
return Collections.emptySet();
|
||||
@@ -222,6 +236,9 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return Collections.unmodifiableSet(tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return rollouts target group
|
||||
*/
|
||||
public List<RolloutTargetGroup> getRolloutTargetGroup() {
|
||||
if (rolloutTargetGroup == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -230,6 +247,11 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return Collections.unmodifiableList(rolloutTargetGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tag
|
||||
* tag
|
||||
* @return boolean true or false
|
||||
*/
|
||||
public boolean addTag(final TargetTag tag) {
|
||||
if (tags == null) {
|
||||
tags = new HashSet<>();
|
||||
@@ -238,6 +260,11 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return tags.add(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tag
|
||||
* tag
|
||||
* @return boolean true or false
|
||||
*/
|
||||
public boolean removeTag(final TargetTag tag) {
|
||||
if (tags == null) {
|
||||
return false;
|
||||
@@ -246,14 +273,25 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return tags.remove(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param assignedDistributionSet
|
||||
* Distribution set
|
||||
*/
|
||||
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
|
||||
this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param controllerId
|
||||
* Controller ID
|
||||
*/
|
||||
public void setControllerId(final String controllerId) {
|
||||
this.controllerId = controllerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of action
|
||||
*/
|
||||
public List<Action> getActions() {
|
||||
if (actions == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -262,6 +300,11 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return Collections.unmodifiableList(actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* Action
|
||||
* @return boolean true or false
|
||||
*/
|
||||
public boolean addAction(final Action action) {
|
||||
if (actions == null) {
|
||||
actions = new ArrayList<>();
|
||||
@@ -285,6 +328,10 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param securityToken
|
||||
* token value
|
||||
*/
|
||||
public void setSecurityToken(final String securityToken) {
|
||||
this.securityToken = securityToken;
|
||||
}
|
||||
@@ -348,10 +395,29 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return updateStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* Target type
|
||||
*/
|
||||
public void setTargetType(final TargetType type) {
|
||||
this.targetType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Distribution set
|
||||
*/
|
||||
public JpaDistributionSet getInstalledDistributionSet() {
|
||||
return installedDistributionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return controller attributes
|
||||
*/
|
||||
public Map<String, String> getControllerAttributes() {
|
||||
return controllerAttributes;
|
||||
}
|
||||
@@ -361,6 +427,9 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
return requestControllerAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return target metadata
|
||||
*/
|
||||
public List<TargetMetadata> getMetadata() {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -375,26 +444,50 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
+ "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address
|
||||
* Address
|
||||
*/
|
||||
public void setAddress(final String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastTargetQuery
|
||||
* last query ID
|
||||
*/
|
||||
public void setLastTargetQuery(final Long lastTargetQuery) {
|
||||
this.lastTargetQuery = lastTargetQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param installationDate
|
||||
* installation date
|
||||
*/
|
||||
public void setInstallationDate(final Long installationDate) {
|
||||
this.installationDate = installationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param installedDistributionSet
|
||||
* Distribution set
|
||||
*/
|
||||
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
|
||||
this.installedDistributionSet = installedDistributionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param updateStatus
|
||||
* Status
|
||||
*/
|
||||
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
|
||||
this.updateStatus = updateStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requestControllerAttributes
|
||||
* Attributes
|
||||
*/
|
||||
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
|
||||
this.requestControllerAttributes = requestControllerAttributes;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetTypeDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A target type defines which distribution set types can or have to be
|
||||
* {@link Target}.
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "sp_target_type", indexes = {
|
||||
@Index(name = "sp_idx_target_type_prim", columnList = "tenant,id") }, uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_target_type_name")})
|
||||
public class JpaTargetType extends AbstractJpaNamedEntity implements TargetType, EventAwareEntity{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "colour", nullable = true, length = TargetType.COLOUR_MAX_SIZE)
|
||||
@Size(max = TargetType.COLOUR_MAX_SIZE)
|
||||
private String colour;
|
||||
|
||||
@CascadeOnDelete
|
||||
@ManyToMany(targetEntity = JpaDistributionSetType.class)
|
||||
@JoinTable(name = "sp_target_type_ds_type_relation", joinColumns = {
|
||||
@JoinColumn(name = "target_type", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_type_relation_target_type"))}, inverseJoinColumns = {
|
||||
@JoinColumn(name = "distribution_set_type", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_type_relation_ds_type"))})
|
||||
private Set<DistributionSetType> distributionSetTypes;
|
||||
|
||||
@OneToMany(targetEntity = JpaTarget.class, mappedBy = "targetType", fetch = FetchType.LAZY)
|
||||
private Set<Target> targets;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public JpaTargetType() {
|
||||
// default public constructor for JPA
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param name
|
||||
* Type name
|
||||
* @param description
|
||||
* Description
|
||||
* @param colour
|
||||
* Colour
|
||||
*/
|
||||
public JpaTargetType(String name, String description, String colour) {
|
||||
super(name,description);
|
||||
this.colour = colour;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dsSetType
|
||||
* Distribution set type
|
||||
* @return Target type
|
||||
*/
|
||||
public JpaTargetType addCompatibleDistributionSetType(final DistributionSetType dsSetType) {
|
||||
if (distributionSetTypes == null) {
|
||||
distributionSetTypes = new HashSet<>();
|
||||
}
|
||||
|
||||
distributionSetTypes.add(dsSetType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dsTypeId
|
||||
* Distribution set type ID
|
||||
* @return Target type
|
||||
*/
|
||||
public JpaTargetType removeDistributionSetType(final Long dsTypeId) {
|
||||
if (distributionSetTypes == null) {
|
||||
return this;
|
||||
}
|
||||
distributionSetTypes.stream().filter(element -> element.getId().equals(dsTypeId)).findAny()
|
||||
.ifPresent(distributionSetTypes::remove);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DistributionSetType> getCompatibleDistributionSetTypes() {
|
||||
|
||||
if (distributionSetTypes == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(distributionSetTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Target> getTargets() {
|
||||
return targets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColour() {
|
||||
return colour;
|
||||
}
|
||||
|
||||
public void setColour(final String colour) {
|
||||
this.colour = colour;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCreateEvent(DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
||||
new TargetTypeCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireUpdateEvent(DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
||||
new TargetTypeUpdatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireDeleteEvent(DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new TargetTypeDeletedEvent(
|
||||
getTenant(), getId(), getClass().getName(), EventPublisherHolder.getInstance().getApplicationId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link TargetType}s. The class provides Spring Data JPQL
|
||||
* Specifications.
|
||||
*
|
||||
*/
|
||||
public final class TargetTypeSpecification {
|
||||
|
||||
private TargetTypeSpecification() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by controllerId
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
*
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasId(final Long id) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTargetType_.id), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by controllerId
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
*
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasTarget(final long id) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final SetJoin<JpaTargetType, JpaTarget> join = targetRoot.join(JpaTargetType_.targets);
|
||||
return cb.equal(join.get(JpaTarget_.id), id);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by controllerId
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
*
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasTarget(final Collection<Long> ids) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final SetJoin<JpaTargetType, JpaTarget> join = targetRoot.join(JpaTargetType_.targets);
|
||||
return join.get(JpaTarget_.id).in(ids);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by controllerId
|
||||
*
|
||||
* @param controllerId
|
||||
* to search for
|
||||
*
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasTargetControllerId(final String controllerId) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final SetJoin<JpaTargetType, JpaTarget> join = targetRoot.join(JpaTargetType_.targets);
|
||||
return cb.equal(join.get(JpaTarget_.controllerId), controllerId);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by controllerId
|
||||
*
|
||||
* @param controllerIds
|
||||
* to search for
|
||||
*
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasTargetControllerIdIn(final Collection<String> controllerIds) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final SetJoin<JpaTargetType, JpaTarget> join = targetRoot.join(JpaTargetType_.targets);
|
||||
return join.get(JpaTarget_.controllerId).in(controllerIds);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by controllerId
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
*
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasIdIn(final Collection<Long> ids) {
|
||||
return (targetRoot, query, cb) -> targetRoot.get(JpaTargetType_.id).in(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s based on a
|
||||
* {@link DistributionSetType} name.
|
||||
*
|
||||
* @param dsTypeId
|
||||
* to search for
|
||||
*
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasDsSetType(final Long dsTypeId) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final SetJoin<JpaTargetType, JpaDistributionSetType> join = targetRoot.join(JpaTargetType_.distributionSetTypes);
|
||||
return cb.equal(join.get(JpaDistributionSetType_.id), dsTypeId);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType} with
|
||||
* given {@link TargetType#getName()} including fetching the
|
||||
* elements list.
|
||||
*
|
||||
* @param name
|
||||
* to search
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasName(final String name) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTargetType_.name), name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
CREATE TABLE sp_target_type
|
||||
(
|
||||
id BIGINT GENERATED always AS IDENTITY NOT NULL,
|
||||
tenant VARCHAR(40) NOT NULL,
|
||||
colour VARCHAR(16),
|
||||
created_at BIGINT NOT NULL,
|
||||
created_by VARCHAR(64) NOT NULL,
|
||||
description VARCHAR(512),
|
||||
last_modified_at BIGINT NOT NULL,
|
||||
last_modified_by VARCHAR(64) NOT NULL,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
optlock_revision INTEGER,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE INDEX sp_idx_target_type_prim
|
||||
ON sp_target_type (tenant, id);
|
||||
|
||||
CREATE TABLE sp_target_type_ds_type_relation
|
||||
(
|
||||
target_type BIGINT NOT NULL,
|
||||
distribution_set_type BIGINT NOT NULL,
|
||||
PRIMARY KEY (target_type, distribution_set_type)
|
||||
);
|
||||
|
||||
ALTER TABLE sp_target_type ADD CONSTRAINT uk_target_type_name UNIQUE (name, tenant);
|
||||
|
||||
ALTER TABLE sp_target ADD COLUMN target_type BIGINT;
|
||||
ALTER TABLE sp_target ADD CONSTRAINT fk_target_relation_target_type FOREIGN KEY (target_type) REFERENCES sp_target_type (id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE sp_target_type_ds_type_relation ADD CONSTRAINT fk_target_type_relation_target_type FOREIGN KEY (target_type) REFERENCES sp_target_type (id) ON DELETE CASCADE;
|
||||
ALTER TABLE sp_target_type_ds_type_relation ADD CONSTRAINT fk_target_type_relation_ds_type FOREIGN KEY (distribution_set_type) REFERENCES sp_distribution_set_type (id) ON DELETE CASCADE;
|
||||
@@ -0,0 +1,50 @@
|
||||
create table sp_target_type
|
||||
(
|
||||
id bigint generated by default as identity,
|
||||
created_at bigint,
|
||||
created_by varchar(64),
|
||||
last_modified_at bigint,
|
||||
last_modified_by varchar(64),
|
||||
optlock_revision bigint,
|
||||
tenant varchar(40) not null,
|
||||
description varchar(512),
|
||||
name varchar(64) not null,
|
||||
colour varchar(16),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table sp_target_type_ds_type_relation
|
||||
(
|
||||
target_type bigint not null,
|
||||
distribution_set_type bigint not null,
|
||||
primary key (target_type, distribution_set_type)
|
||||
);
|
||||
|
||||
alter table sp_target_type
|
||||
add constraint uk_target_type_name unique (name, tenant);
|
||||
|
||||
create index sp_idx_target_type_prim on sp_target_type (tenant, id);
|
||||
|
||||
alter table sp_target
|
||||
add column target_type bigint;
|
||||
|
||||
alter table sp_target
|
||||
add constraint fk_target_relation_target_type
|
||||
foreign key (target_type)
|
||||
references sp_target_type
|
||||
on delete set null;
|
||||
|
||||
alter table sp_target_type_ds_type_relation
|
||||
add constraint fk_target_type_relation_target_type
|
||||
foreign key (target_type)
|
||||
references sp_target_type
|
||||
on delete cascade;
|
||||
|
||||
alter table sp_target_type_ds_type_relation
|
||||
add constraint fk_target_type_relation_ds_type
|
||||
foreign key (distribution_set_type)
|
||||
references sp_distribution_set_type
|
||||
on delete cascade;
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
create table sp_target_type
|
||||
(
|
||||
id bigint not null auto_increment,
|
||||
created_at bigint,
|
||||
created_by varchar(64),
|
||||
last_modified_at bigint,
|
||||
last_modified_by varchar(64),
|
||||
optlock_revision bigint,
|
||||
tenant varchar(40) not null,
|
||||
description varchar(512),
|
||||
name varchar(64) not null,
|
||||
colour varchar(16),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table sp_target_type_ds_type_relation
|
||||
(
|
||||
target_type bigint not null,
|
||||
distribution_set_type bigint not null,
|
||||
primary key (target_type, distribution_set_type)
|
||||
);
|
||||
|
||||
alter table sp_target_type
|
||||
add constraint uk_target_type_name unique (name, tenant);
|
||||
|
||||
create index sp_idx_target_type_prim on sp_target_type (tenant, id);
|
||||
|
||||
alter table sp_target
|
||||
add column target_type bigint;
|
||||
|
||||
alter table sp_target
|
||||
add constraint fk_target_relation_target_type
|
||||
foreign key (target_type)
|
||||
references sp_target_type (id)
|
||||
on delete set null;
|
||||
|
||||
alter table sp_target_type_ds_type_relation
|
||||
add constraint fk_target_type_relation_target_type
|
||||
foreign key (target_type)
|
||||
references sp_target_type (id)
|
||||
on delete cascade;
|
||||
|
||||
alter table sp_target_type_ds_type_relation
|
||||
add constraint fk_target_type_relation_ds_type
|
||||
foreign key (distribution_set_type)
|
||||
references sp_distribution_set_type (id)
|
||||
on delete cascade;
|
||||
@@ -0,0 +1,65 @@
|
||||
-- ------------ Write CREATE-SEQUENCE-stage scripts -----------
|
||||
|
||||
CREATE SEQUENCE IF NOT EXISTS sp_target_type_seq
|
||||
INCREMENT BY 1
|
||||
START WITH 1
|
||||
NO CYCLE;
|
||||
|
||||
-- ------------ Write CREATE-TABLE-stage scripts -----------
|
||||
|
||||
CREATE TABLE sp_target_type(
|
||||
id BIGINT NOT NULL DEFAULT nextval('sp_target_type_seq'),
|
||||
created_at BIGINT,
|
||||
created_by VARCHAR(64),
|
||||
last_modified_at BIGINT,
|
||||
last_modified_by VARCHAR(64),
|
||||
optlock_revision BIGINT,
|
||||
tenant VARCHAR(40) NOT NULL,
|
||||
description VARCHAR(512),
|
||||
name VARCHAR(64),
|
||||
colour VARCHAR(16)
|
||||
)
|
||||
WITH (
|
||||
OIDS=FALSE
|
||||
);
|
||||
|
||||
CREATE TABLE sp_target_type_ds_type_relation(
|
||||
target_type BIGINT NOT NULL,
|
||||
distribution_set_type BIGINT NOT NULL
|
||||
)
|
||||
WITH (
|
||||
OIDS=FALSE
|
||||
);
|
||||
|
||||
-- ------------ Alter Table and Write INDEX scripts -----------
|
||||
|
||||
ALTER TABLE sp_target_type
|
||||
ADD CONSTRAINT pk_sp_target_type PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE sp_target_type
|
||||
ADD CONSTRAINT uk_target_type_name UNIQUE (name, tenant);
|
||||
|
||||
CREATE INDEX sp_idx_target_type_prim
|
||||
ON sp_target_type
|
||||
USING BTREE (tenant, id);
|
||||
|
||||
ALTER TABLE sp_target
|
||||
ADD COLUMN target_type BIGINT;
|
||||
|
||||
ALTER TABLE sp_target
|
||||
ADD CONSTRAINT fk_target_relation_target_type FOREIGN KEY (target_type)
|
||||
REFERENCES sp_target_type (id)
|
||||
ON UPDATE RESTRICT
|
||||
ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE sp_target_type_ds_type_relation
|
||||
ADD CONSTRAINT fk_target_type_relation_target_type FOREIGN KEY (target_type)
|
||||
REFERENCES sp_target_type (id)
|
||||
ON UPDATE RESTRICT
|
||||
ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE sp_target_type_ds_type_relation
|
||||
ADD CONSTRAINT fk_target_type_relation_ds_type FOREIGN KEY (distribution_set_type)
|
||||
REFERENCES sp_distribution_set_type (id)
|
||||
ON UPDATE RESTRICT
|
||||
ON DELETE CASCADE;
|
||||
@@ -0,0 +1,27 @@
|
||||
CREATE TABLE sp_target_type
|
||||
(
|
||||
id NUMERIC(19) IDENTITY NOT NULL,
|
||||
tenant VARCHAR(40) NOT NULL,
|
||||
colour VARCHAR(16) NULL,
|
||||
created_at NUMERIC(19) NOT NULL,
|
||||
created_by VARCHAR(64) NOT NULL,
|
||||
description VARCHAR(512) NULL,
|
||||
last_modified_at NUMERIC(19) NOT NULL,
|
||||
last_modified_by VARCHAR(64) NOT NULL,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
optlock_revision INTEGER NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
CREATE INDEX sp_idx_target_type_prim ON sp_target_type (tenant, id);
|
||||
CREATE TABLE sp_target_type_ds_type_relation
|
||||
(
|
||||
target_type NUMERIC(19) NOT NULL,
|
||||
distribution_set_type NUMERIC(19) NOT NULL,
|
||||
PRIMARY KEY (target_type, distribution_set_type)
|
||||
);
|
||||
ALTER TABLE sp_target_type ADD CONSTRAINT uk_target_type_name UNIQUE (name, tenant);
|
||||
ALTER TABLE sp_target ADD target_type NUMERIC(19) NULL;
|
||||
ALTER TABLE sp_target ADD CONSTRAINT fk_target_relation_target_type FOREIGN KEY (target_type) REFERENCES sp_target_type (id) ON DELETE SET NULL;
|
||||
ALTER TABLE sp_target_type_ds_type_relation ADD CONSTRAINT fk_target_type_relation_target_type FOREIGN KEY (target_type) REFERENCES sp_target_type (id) ON DELETE CASCADE;
|
||||
ALTER TABLE sp_target_type_ds_type_relation ADD CONSTRAINT fk_target_type_relation_ds_type FOREIGN KEY (distribution_set_type) REFERENCES sp_distribution_set_type (id) ON DELETE CASCADE;
|
||||
|
||||
@@ -76,6 +76,9 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
@Autowired
|
||||
protected TargetTagRepository targetTagRepository;
|
||||
|
||||
@Autowired
|
||||
protected TargetTypeRepository targetTypeRepository;
|
||||
|
||||
@Autowired
|
||||
protected DistributionSetTagRepository distributionSetTagRepository;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
@@ -27,6 +28,7 @@ import javax.validation.ConstraintViolationException;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||
@@ -53,6 +55,7 @@ import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||
@@ -1038,6 +1041,67 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(updated.getTarget().getId()).isEqualTo(target.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(allSpPermissions = true)
|
||||
@Description("Checks that target type for a target can be created, updated and unassigned.")
|
||||
public void createAndUpdateTargetTypeInTarget() {
|
||||
// create a target type
|
||||
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype", 2);
|
||||
assertThat(targetTypes).hasSize(2);
|
||||
// create a target
|
||||
final Target target = testdataFactory.createTarget("target1", "testtarget", targetTypes.get(0).getId());
|
||||
// initial opt lock revision must be one
|
||||
Optional<JpaTarget> targetFound = targetRepository.findById(target.getId());
|
||||
assertThat(targetFound).isPresent();
|
||||
assertThat(targetFound.get().getOptLockRevision()).isEqualTo(1);
|
||||
assertThat(targetFound.get().getTargetType().getId()).isEqualTo(targetTypes.get(0).getId());
|
||||
|
||||
// update the target type
|
||||
TargetUpdate targetUpdate = entityFactory.target().update(target.getControllerId()).targetType(targetTypes.get(1).getId());
|
||||
targetManagement.update(targetUpdate);
|
||||
|
||||
// opt lock revision must be changed
|
||||
Optional<JpaTarget> targetFound1 = targetRepository.findById(target.getId());
|
||||
assertThat(targetFound1).isPresent();
|
||||
assertThat(targetFound1.get().getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(targetFound1.get().getTargetType().getId()).isEqualTo(targetTypes.get(1).getId());
|
||||
|
||||
// unassign the target type
|
||||
targetManagement.unAssignType(target.getControllerId());
|
||||
|
||||
// opt lock revision must be changed
|
||||
Optional<JpaTarget> targetFound2 = targetRepository.findById(target.getId());
|
||||
assertThat(targetFound2).isPresent();
|
||||
assertThat(targetFound2.get().getOptLockRevision()).isEqualTo(3);
|
||||
assertThat(targetFound2.get().getTargetType()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(allSpPermissions = true)
|
||||
@Description("Checks that target type to a target can be assigned.")
|
||||
public void assignTargetTypeInTarget() {
|
||||
// create a target
|
||||
final Target target = testdataFactory.createTarget("target1", "testtarget");
|
||||
// initial opt lock revision must be one
|
||||
Optional<JpaTarget> targetFound = targetRepository.findById(target.getId());
|
||||
assertThat(targetFound).isPresent();
|
||||
assertThat(targetFound.get().getOptLockRevision()).isEqualTo(1);
|
||||
assertThat(targetFound.get().getTargetType()).isNull();
|
||||
|
||||
// create a target type
|
||||
TargetType targetType = testdataFactory.findOrCreateTargetType("targettype");
|
||||
assertThat(targetType).isNotNull();
|
||||
|
||||
// assign target type to target
|
||||
targetManagement.assignType(targetFound.get().getControllerId(), targetType.getId());
|
||||
|
||||
// opt lock revision must be changed
|
||||
Optional<JpaTarget> targetFound1 = targetRepository.findById(target.getId());
|
||||
assertThat(targetFound1).isPresent();
|
||||
assertThat(targetFound1.get().getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(targetFound1.get().getTargetType().getId()).isEqualTo(targetType.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Queries and loads the metadata related to a given target.")
|
||||
public void findAllTargetMetadataByControllerId() {
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Step;
|
||||
import io.qameta.allure.Story;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@Feature("Component Tests - Repository")
|
||||
@Story("Target Type Management")
|
||||
public class TargetTypeManagementTest extends AbstractJpaIntegrationTest{
|
||||
|
||||
@Test
|
||||
@Description("Verifies that management get access react as specified on calls for non existing entities by means "
|
||||
+ "of Optional not present.")
|
||||
@ExpectEvents({ @Expect(type = TargetTypeCreatedEvent.class, count = 0) })
|
||||
public void nonExistingEntityAccessReturnsNotPresent() {
|
||||
assertThat(targetTypeManagement.get(NOT_EXIST_IDL)).isNotPresent();
|
||||
assertThat(targetTypeManagement.getByName(NOT_EXIST_ID)).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that management queries react as specified on calls for non existing entities "
|
||||
+ " by means of throwing EntityNotFoundException.")
|
||||
@ExpectEvents({ @Expect(type = TargetTypeUpdatedEvent.class, count = 0) })
|
||||
public void entityQueriesReferringToNotExistingEntitiesThrowsException() {
|
||||
verifyThrownExceptionBy(() -> targetTypeManagement.delete(NOT_EXIST_IDL), "TargetType");
|
||||
verifyThrownExceptionBy(() -> targetTypeManagement.update(entityFactory.targetType().update(NOT_EXIST_IDL)),
|
||||
"TargetType");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that a target type with invalid properties cannot be created or updated")
|
||||
public void createAndUpdateTargetTypeWithInvalidFields() {
|
||||
final TargetType targetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("targettype1").description("targettypedes1"));
|
||||
|
||||
createAndUpdateTargetTypeWithInvalidDescription(targetType);
|
||||
createAndUpdateTargetTypeWithInvalidColour(targetType);
|
||||
createAndUpdateTargetTypeWithInvalidName(targetType);
|
||||
}
|
||||
|
||||
@Step
|
||||
private void createAndUpdateTargetTypeWithInvalidDescription(final TargetType targetType) {
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement.create(
|
||||
entityFactory.targetType().create().name("a").description(RandomStringUtils.randomAlphanumeric(TargetType.DESCRIPTION_MAX_SIZE + 1))))
|
||||
.as("targetType with too long description should not be created");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
|
||||
() -> targetTypeManagement.create(entityFactory.targetType().create().name("a").description(INVALID_TEXT_HTML)))
|
||||
.as("targetType with invalid description should not be created");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement.update(
|
||||
entityFactory.targetType().update(targetType.getId()).description(RandomStringUtils.randomAlphanumeric(TargetType.DESCRIPTION_MAX_SIZE + 1))))
|
||||
.as("targetType with too long description should not be updated");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement
|
||||
.update(entityFactory.targetType().update(targetType.getId()).description(INVALID_TEXT_HTML)))
|
||||
.as("targetType with invalid description should not be updated");
|
||||
}
|
||||
|
||||
@Step
|
||||
private void createAndUpdateTargetTypeWithInvalidColour(final TargetType targetType) {
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement.create(
|
||||
entityFactory.targetType().create().name("a").colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))))
|
||||
.as("targetType with too long colour should not be created");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
|
||||
() -> targetTypeManagement.create(entityFactory.targetType().create().name("a").colour(INVALID_TEXT_HTML)))
|
||||
.as("targetType with invalid colour should not be created");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement.update(
|
||||
entityFactory.targetType().update(targetType.getId()).colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))))
|
||||
.as("targetType with too long colour should not be updated");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
|
||||
() -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).colour(INVALID_TEXT_HTML)))
|
||||
.as("targetType with invalid colour should not be updated");
|
||||
}
|
||||
|
||||
@Step
|
||||
private void createAndUpdateTargetTypeWithInvalidName(final TargetType targetType) {
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name(RandomStringUtils.randomAlphanumeric(
|
||||
NamedEntity.NAME_MAX_SIZE + 1))))
|
||||
.as("targetType with too long name should not be created");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement.create(entityFactory.targetType().create().name(INVALID_TEXT_HTML)))
|
||||
.as("targetType with invalid name should not be created");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement
|
||||
.update(entityFactory.targetType().update(targetType.getId()).name(RandomStringUtils.randomAlphanumeric(
|
||||
NamedEntity.NAME_MAX_SIZE + 1))))
|
||||
.as("targetType with too long name should not be updated");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
|
||||
() -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name(INVALID_TEXT_HTML)))
|
||||
.as("targetType with invalid name should not be updated");
|
||||
|
||||
assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("")))
|
||||
.as("targetType with too short name should not be updated");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the successful assignment of compatible distribution set types to a target type")
|
||||
public void assignCompatibleDistributionSetTypesToTargetType(){
|
||||
final TargetType targetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("targettype1").description("targettypedes1"));
|
||||
DistributionSetType distributionSetType = testdataFactory.findOrCreateDistributionSetType("testDst", "dst1");
|
||||
targetTypeManagement.assignCompatibleDistributionSetTypes(targetType.getId(), Collections.singletonList(distributionSetType.getId()));
|
||||
|
||||
Optional<JpaTargetType> targetTypeWithDsTypes = targetTypeRepository.findById(targetType.getId());
|
||||
assertThat(targetTypeWithDsTypes).isPresent();
|
||||
assertThat(targetTypeWithDsTypes.get().getCompatibleDistributionSetTypes()).extracting("key").contains("testDst");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the successful removal of compatible distribution set types to a target type")
|
||||
public void unassignCompatibleDistributionSetTypesToTargetType(){
|
||||
final TargetType targetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("targettype11").description("targettypedes11"));
|
||||
DistributionSetType distributionSetType = testdataFactory.findOrCreateDistributionSetType("testDst1", "dst11");
|
||||
targetTypeManagement.assignCompatibleDistributionSetTypes(targetType.getId(), Collections.singletonList(distributionSetType.getId()));
|
||||
Optional<JpaTargetType> targetTypeWithDsTypes = targetTypeRepository.findById(targetType.getId());
|
||||
assertThat(targetTypeWithDsTypes).isPresent();
|
||||
assertThat(targetTypeWithDsTypes.get().getCompatibleDistributionSetTypes()).extracting("key").contains("testDst1");
|
||||
targetTypeManagement.unassignDistributionSetType(targetType.getId(),distributionSetType.getId());
|
||||
Optional<JpaTargetType> targetTypeWithDsTypes1 = targetTypeRepository.findById(targetType.getId());
|
||||
assertThat(targetTypeWithDsTypes1).isPresent();
|
||||
assertThat(targetTypeWithDsTypes1.get().getCompatibleDistributionSetTypes()).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that all types are retrieved through repository.")
|
||||
public void findAllTargetTypes() {
|
||||
testdataFactory.createTargetTypes("targettype", 10);
|
||||
assertThat(targetTypeRepository.findAll()).as("Target type size").hasSize(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that a created target type is persisted in the repository as defined.")
|
||||
public void createTargetType() {
|
||||
final TargetType targetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("targettype1").description("targettypedes1").colour("colour1"));
|
||||
|
||||
assertThat(targetTypeRepository.findByName("targettype1").get().getDescription()).as("type found")
|
||||
.isEqualTo("targettypedes1");
|
||||
assertThat(targetTypeManagement.getByName("targettype1").get().getColour()).as("type found").isEqualTo("colour1");
|
||||
assertThat(targetTypeManagement.get(targetType.getId()).get().getColour()).as("type found").isEqualTo("colour1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that a deleted target type is removed from the repository as defined.")
|
||||
public void deleteTargetType() {
|
||||
// create test data
|
||||
final TargetType targetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("targettype11").description("targettypedes11"));
|
||||
assertThat(targetTypeRepository.findByName("targettype11").get().getDescription()).as("type found")
|
||||
.isEqualTo("targettypedes11");
|
||||
targetTypeManagement.delete(targetType.getId());
|
||||
assertThat(targetTypeRepository.findById(targetType.getId())).as("No target type should be found").isNotPresent();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the name update of a target type.")
|
||||
public void updateTargetType() {
|
||||
final TargetType targetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("targettype111").description("targettypedes111"));
|
||||
assertThat(targetTypeRepository.findByName("targettype111").get().getDescription()).as("type found")
|
||||
.isEqualTo("targettypedes111");
|
||||
targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("updatedtargettype111"));
|
||||
assertThat(targetTypeRepository.findByName("updatedtargettype111")).as("Updated target type should be found").isPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that a target type cannot be created if one exists already with that name (expects EntityAlreadyExistsException).")
|
||||
public void failedDuplicateTargetTypeNameException() {
|
||||
targetTypeManagement.create(entityFactory.targetType().create().name("targettype123"));
|
||||
assertThrows(EntityAlreadyExistsException.class, () -> targetTypeManagement.create(entityFactory.targetType().create().name("targettype123")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that a target type cannot be updated to a name that already exists (expects EntityAlreadyExistsException).")
|
||||
public void failedDuplicateTargetTypeNameExceptionAfterUpdate() {
|
||||
targetTypeManagement.create(entityFactory.targetType().create().name("targettype1234"));
|
||||
TargetType targetType = targetTypeManagement.create(entityFactory.targetType().create().name("targettype12345"));
|
||||
assertThrows(EntityAlreadyExistsException.class, () -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("targettype1234")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.event;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -20,10 +21,13 @@ import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetTypeDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.event.RepositoryEntityEventTest.RepositoryTestConfiguration;
|
||||
@@ -31,6 +35,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -88,6 +93,38 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(targetDeletedEvent.getEntityId()).isEqualTo(createdTarget.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the target type created event is published when a target type has been created")
|
||||
public void targetTypeCreatedEventIsPublished() throws InterruptedException {
|
||||
TargetType createdTargetType = testdataFactory.findOrCreateTargetType("targettype");
|
||||
|
||||
TargetTypeCreatedEvent targetTypeCreatedEvent = eventListener.waitForEvent(TargetTypeCreatedEvent.class);
|
||||
assertThat(targetTypeCreatedEvent).isNotNull();
|
||||
assertThat(targetTypeCreatedEvent.getEntity().getId()).isEqualTo(createdTargetType.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the target type updated event is published when a target type has been updated")
|
||||
public void targetTypeUpdatedEventIsPublished() throws InterruptedException {
|
||||
TargetType createdTargetType = testdataFactory.findOrCreateTargetType("targettype");
|
||||
targetTypeManagement.update(entityFactory.targetType().update(createdTargetType.getId()).name("updatedtargettype"));
|
||||
|
||||
TargetTypeUpdatedEvent targetTypeUpdatedEvent = eventListener.waitForEvent(TargetTypeUpdatedEvent.class);
|
||||
assertThat(targetTypeUpdatedEvent).isNotNull();
|
||||
assertThat(targetTypeUpdatedEvent.getEntity().getId()).isEqualTo(createdTargetType.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the target type deleted event is published when a target type has been deleted")
|
||||
public void targetTypeDeletedEventIsPublished() throws InterruptedException {
|
||||
TargetType createdTargetType = testdataFactory.findOrCreateTargetType("targettype");
|
||||
targetTypeManagement.delete(createdTargetType.getId());
|
||||
|
||||
TargetTypeDeletedEvent targetTypeDeletedEvent = eventListener.waitForEvent(TargetTypeDeletedEvent.class);
|
||||
assertThat(targetTypeDeletedEvent).isNotNull();
|
||||
assertThat(targetTypeDeletedEvent.getEntityId()).isEqualTo(createdTargetType.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the rollout deleted event is published when a rollout has been deleted")
|
||||
public void rolloutDeletedEventIsPublished() throws InterruptedException {
|
||||
|
||||
Reference in New Issue
Block a user