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:
@@ -29,6 +29,7 @@ Supported HTTP-methods are:
|
|||||||
Available Management APIs resources are:
|
Available Management APIs resources are:
|
||||||
|
|
||||||
- [Targets](/hawkbit/apis/mgmt/targets/)
|
- [Targets](/hawkbit/apis/mgmt/targets/)
|
||||||
|
- [Target types](/hawkbit/apis/mgmt/targettypess/)
|
||||||
- [Distribution sets](/hawkbit/apis/mgmt/distributionsets/)
|
- [Distribution sets](/hawkbit/apis/mgmt/distributionsets/)
|
||||||
- [Distribution set types](/hawkbit/apis/mgmt/distributionsettypes/)
|
- [Distribution set types](/hawkbit/apis/mgmt/distributionsettypes/)
|
||||||
- [Software modules](/hawkbit/apis/mgmt/softwaremodules/)
|
- [Software modules](/hawkbit/apis/mgmt/softwaremodules/)
|
||||||
|
|||||||
7
docs/content/apis/mgmt/targettypes.md
Normal file
7
docs/content/apis/mgmt/targettypes.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Target Types API
|
||||||
|
parent: Management API
|
||||||
|
weight: -100
|
||||||
|
---
|
||||||
|
|
||||||
|
<iframe width="100%" height="800px" frameborder="0" src="../../../rest-api/targettypes-api-guide/"></iframe>
|
||||||
@@ -275,7 +275,9 @@ public enum SpServerError {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE("hawkbit.server.error.noWeightProvidedInMultiAssignmentMode",
|
SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE("hawkbit.server.error.noWeightProvidedInMultiAssignmentMode",
|
||||||
"The requested operation requires a weight to be specified when multi assignments is enabled.");
|
"The requested operation requires a weight to be specified when multi assignments is enabled."),
|
||||||
|
|
||||||
|
SP_TARGET_TYPE_IN_USE("hawkbit.server.error.target.type.used", "Target type is still in use by a target.");
|
||||||
|
|
||||||
private final String key;
|
private final String key;
|
||||||
private final String message;
|
private final String message;
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describing the fields of the TargetType model which can be used in
|
||||||
|
* the REST API
|
||||||
|
*/
|
||||||
|
public enum TargetTypeFields implements FieldNameProvider {
|
||||||
|
/**
|
||||||
|
* The name field.
|
||||||
|
*/
|
||||||
|
NAME("name"),
|
||||||
|
/**
|
||||||
|
* The description field.
|
||||||
|
*/
|
||||||
|
DESCRIPTION("description"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id field.
|
||||||
|
*/
|
||||||
|
ID("id");
|
||||||
|
|
||||||
|
private final String fieldName;
|
||||||
|
|
||||||
|
TargetTypeFields(final String fieldName) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldName() {
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeBuilder;
|
|||||||
import org.eclipse.hawkbit.repository.builder.TagBuilder;
|
import org.eclipse.hawkbit.repository.builder.TagBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||||
|
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||||
|
|
||||||
@@ -109,6 +110,11 @@ public interface EntityFactory {
|
|||||||
*/
|
*/
|
||||||
TargetBuilder target();
|
TargetBuilder target();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@link TargetTypeBuilder} object
|
||||||
|
*/
|
||||||
|
TargetTypeBuilder targetType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@link TargetFilterQueryBuilder} object
|
* @return {@link TargetFilterQueryBuilder} object
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -106,4 +106,9 @@ public interface QuotaManagement {
|
|||||||
*/
|
*/
|
||||||
long getMaxArtifactStorage();
|
long getMaxArtifactStorage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the maximum number of distribution set types per target type
|
||||||
|
*/
|
||||||
|
int getMaxDistributionSetTypesPerTargetType();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.repository.model.Target;
|
|||||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -598,6 +599,30 @@ public interface TargetManagement {
|
|||||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||||
Target unAssignTag(@NotEmpty String controllerID, long targetTagId);
|
Target unAssignTag(@NotEmpty String controllerID, long targetTagId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Un-assign a {@link TargetType} assignment to given {@link Target}.
|
||||||
|
*
|
||||||
|
* @param controllerID
|
||||||
|
* to un-assign for
|
||||||
|
* @return the unassigned target
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||||
|
Target unAssignType(@NotEmpty String controllerID);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a {@link TargetType} assignment to given {@link Target}.
|
||||||
|
*
|
||||||
|
* @param controllerID
|
||||||
|
* to un-assign for
|
||||||
|
* @return the unassigned target
|
||||||
|
*
|
||||||
|
* @throws EntityNotFoundException
|
||||||
|
* if TargetType with given target ID does not exist
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||||
|
Target assignType(@NotEmpty String controllerID, @NotNull long targetTypeId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* updates the {@link Target}.
|
* updates the {@link Target}.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||||
|
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||||
|
import org.eclipse.hawkbit.repository.builder.TargetTypeUpdate;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Slice;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Management service for {@link TargetType}s.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface TargetTypeManagement {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* as {@link TargetType#getName()}
|
||||||
|
* @return {@link TargetType}
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
Optional<TargetType> getByName(@NotEmpty String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return total count
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
long count();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param create
|
||||||
|
* TargetTypeCreate
|
||||||
|
* @return targetType
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_CREATE_TARGET)
|
||||||
|
TargetType create(@NotNull @Valid TargetTypeCreate create);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param creates
|
||||||
|
* List of TargetTypeCreate
|
||||||
|
* @return List of targetType
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_CREATE_TARGET)
|
||||||
|
List<TargetType> create(@NotEmpty @Valid Collection<TargetTypeCreate> creates);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id targetTypeId
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_DELETE_TARGET)
|
||||||
|
void delete(@NotNull Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pageable
|
||||||
|
* Page
|
||||||
|
* @return TargetType page
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
Page<TargetType> findAll(@NotNull Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pageable
|
||||||
|
* Page
|
||||||
|
* @param rsqlParam
|
||||||
|
* query param
|
||||||
|
* @return Target type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
Page<TargetType> findByRsql(@NotNull Pageable pageable, @NotEmpty String rsqlParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* Target type ID
|
||||||
|
* @return Target Type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
Optional<TargetType> get(long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetId
|
||||||
|
* Target ID
|
||||||
|
* @return Target Type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
Optional<TargetType> findByTargetId(long targetId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetIds
|
||||||
|
* List of Target ID
|
||||||
|
* @return Target Type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
List<TargetType> findByTargetIds(Collection<Long> targetIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param controllerId
|
||||||
|
* Target controller ID
|
||||||
|
* @return Target Type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
Optional<TargetType> findByTargetControllerId(String controllerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param controllerIds
|
||||||
|
* List of Target controller ID
|
||||||
|
* @return Target Type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
List<TargetType> findByTargetControllerIds(Collection<String> controllerIds);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ids
|
||||||
|
* List of Target type ID
|
||||||
|
* @return Target type list
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
|
List<TargetType> get(@NotEmpty Collection<Long> ids);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param update
|
||||||
|
* TargetTypeUpdate
|
||||||
|
* @return Target Type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||||
|
TargetType update(@NotNull @Valid TargetTypeUpdate update);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetTypeId
|
||||||
|
* Target type ID
|
||||||
|
* @param distributionSetTypeIds
|
||||||
|
* Distribution set ID
|
||||||
|
* @return Target type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||||
|
TargetType assignCompatibleDistributionSetTypes(long targetTypeId,
|
||||||
|
@NotEmpty Collection<Long> distributionSetTypeIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetTypeId
|
||||||
|
* Target type ID
|
||||||
|
* @param distributionSetTypeIds
|
||||||
|
* Distribution set ID
|
||||||
|
* @return Target type
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||||
|
TargetType unassignDistributionSetType(long targetTypeId, long distributionSetTypeIds);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -46,6 +46,13 @@ public interface TargetCreate {
|
|||||||
*/
|
*/
|
||||||
TargetCreate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
|
TargetCreate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetTypeId
|
||||||
|
* for {@link Target#getTargetType()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetCreate targetType(Long targetTypeId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param securityToken
|
* @param securityToken
|
||||||
* for {@link Target#getSecurityToken()} is generated with a
|
* for {@link Target#getSecurityToken()} is generated with a
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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.builder;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for {@link TargetType}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface TargetTypeBuilder {
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* of the updatable entity
|
||||||
|
* @return builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeUpdate update(long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeCreate create();
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* 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.builder;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||||
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
|
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder to create a new {@link TargetType} entry. Defines all fields
|
||||||
|
* that can be set at creation time. Other fields are set by the repository
|
||||||
|
* automatically, e.g. {@link BaseEntity#getCreatedAt()}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface TargetTypeCreate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* for {@link TargetType#getName()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeCreate name(@Size(min = 1, max = NamedEntity.NAME_MAX_SIZE) @NotEmpty String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param description
|
||||||
|
* for {@link TargetType#getDescription()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeCreate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param colour
|
||||||
|
* for {@link TargetType#getColour()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeCreate colour(@Size(max = TargetType.COLOUR_MAX_SIZE) String colour);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param compatible
|
||||||
|
* for {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeCreate compatible(@NotEmpty Collection<Long> compatible);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param compatible
|
||||||
|
* for {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
default TargetTypeCreate compatible(@NotNull final Long compatible) {
|
||||||
|
return compatible(Collections.singletonList(compatible));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param compatible
|
||||||
|
* for {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
default TargetTypeCreate compatible(@NotNull final DistributionSetType compatible) {
|
||||||
|
return compatible(compatible.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return peek on current state of {@link TargetType} in the
|
||||||
|
* builder
|
||||||
|
*/
|
||||||
|
TargetType build();
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 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.builder;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder to update an existing {@link TargetType} entry. Defines all
|
||||||
|
* fields that can be updated.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface TargetTypeUpdate {
|
||||||
|
/**
|
||||||
|
* @param description
|
||||||
|
* for {@link TargetType#getDescription()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeUpdate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param colour
|
||||||
|
* for {@link TargetType#getColour()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeUpdate colour(@Size(max = TargetType.COLOUR_MAX_SIZE) String colour);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* Name
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetTypeUpdate name(@Size(max = TargetType.NAME_MAX_SIZE) String name);
|
||||||
|
}
|
||||||
@@ -43,6 +43,13 @@ public interface TargetUpdate {
|
|||||||
*/
|
*/
|
||||||
TargetUpdate securityToken(@Size(min = 1, max = Target.SECURITY_TOKEN_MAX_SIZE) @NotNull String securityToken);
|
TargetUpdate securityToken(@Size(min = 1, max = Target.SECURITY_TOKEN_MAX_SIZE) @NotNull String securityToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetTypeId
|
||||||
|
* for {@link Target#getTargetType()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetUpdate targetType(@NotNull Long targetTypeId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param address
|
* @param address
|
||||||
* for {@link Target#getAddress()}
|
* for {@link Target#getAddress()}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* 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.event.remote;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.event.entity.EntityDeletedEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Defines the remote event of deleting a {@link TargetType}.
|
||||||
|
*/
|
||||||
|
public class TargetTypeDeletedEvent extends RemoteIdEvent implements EntityDeletedEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public TargetTypeDeletedEvent() {
|
||||||
|
// for serialization libs like jackson
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for json serialization.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant
|
||||||
|
* @param entityId
|
||||||
|
* the entity id
|
||||||
|
* @param entityClass
|
||||||
|
* the entity class
|
||||||
|
* @param applicationId
|
||||||
|
* the origin application id
|
||||||
|
*/
|
||||||
|
public TargetTypeDeletedEvent(final String tenant, final Long entityId, final String entityClass,
|
||||||
|
final String applicationId) {
|
||||||
|
super(entityId, tenant, entityClass, applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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.event.remote.entity;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the remote event of creating a new {@link TargetType}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TargetTypeCreatedEvent extends RemoteEntityEvent<TargetType>
|
||||||
|
implements EntityCreatedEvent {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public TargetTypeCreatedEvent() {
|
||||||
|
// for serialization libs like jackson
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param baseEntity
|
||||||
|
* the TargetType
|
||||||
|
* @param applicationId
|
||||||
|
* the origin application id
|
||||||
|
*/
|
||||||
|
public TargetTypeCreatedEvent(final TargetType baseEntity, final String applicationId) {
|
||||||
|
super(baseEntity, applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 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.event.remote.entity;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the remote event for updating a {@link TargetType}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TargetTypeUpdatedEvent extends RemoteEntityEvent<TargetType>
|
||||||
|
implements EntityUpdatedEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public TargetTypeUpdatedEvent() {
|
||||||
|
// for serialization libs like jackson
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param baseEntity
|
||||||
|
* TargetType
|
||||||
|
* @param applicationId
|
||||||
|
* the origin application id
|
||||||
|
*/
|
||||||
|
public TargetTypeUpdatedEvent(final TargetType baseEntity, final String applicationId) {
|
||||||
|
super(baseEntity, applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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.exception;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the {@link DistributionSetTypeNotInTargetTypeException} is thrown when a
|
||||||
|
* {@link DistributionSetType} is requested as part of a {@link TargetType} but
|
||||||
|
* is not returned in {@link TargetType#getCompatibleDistributionSetTypes()}.
|
||||||
|
*/
|
||||||
|
public class DistributionSetTypeNotInTargetTypeException extends EntityNotFoundException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param distributionSetTypeId
|
||||||
|
* that is not part of given {@link TargetType}
|
||||||
|
* @param targetTypeId
|
||||||
|
* of the {@link TargetType} where given
|
||||||
|
* {@link DistributionSetType} is not part of
|
||||||
|
*/
|
||||||
|
public DistributionSetTypeNotInTargetTypeException(final Long distributionSetTypeId,
|
||||||
|
final Long targetTypeId) {
|
||||||
|
super(DistributionSetType.class.getSimpleName() + " with id {" + distributionSetTypeId + "} is not part of "
|
||||||
|
+ TargetType.class.getSimpleName() + " with id {" + targetTypeId + "}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 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.exception;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||||
|
import org.eclipse.hawkbit.exception.SpServerError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown if target type is assigned
|
||||||
|
*/
|
||||||
|
public class TargetTypeInUseException extends AbstractServerRtException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final SpServerError THIS_ERROR = SpServerError.SP_TARGET_TYPE_IN_USE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public TargetTypeInUseException() {
|
||||||
|
super(THIS_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameterized constructor.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* of the exception
|
||||||
|
*/
|
||||||
|
public TargetTypeInUseException(final Throwable cause) {
|
||||||
|
super(THIS_ERROR, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameterized constructor.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* of the exception
|
||||||
|
* @param cause
|
||||||
|
* of the exception
|
||||||
|
*/
|
||||||
|
public TargetTypeInUseException(final String message, final Throwable cause) {
|
||||||
|
super(message, THIS_ERROR, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameterized constructor.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* of the exception
|
||||||
|
*/
|
||||||
|
public TargetTypeInUseException(final String message) {
|
||||||
|
super(message, THIS_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -85,6 +85,11 @@ public interface Target extends NamedEntity {
|
|||||||
*/
|
*/
|
||||||
TargetUpdateStatus getUpdateStatus();
|
TargetUpdateStatus getUpdateStatus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Target type {@link TargetType}.
|
||||||
|
*/
|
||||||
|
TargetType getTargetType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the poll time which holds the last poll time of the target, the
|
* @return the poll time which holds the last poll time of the target, the
|
||||||
* next poll time and the overdue time. In case the
|
* next poll time and the overdue time. In case the
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TargetType} is an abstract definition for
|
||||||
|
* {@link Target}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface TargetType extends NamedEntity {
|
||||||
|
/**
|
||||||
|
* Maximum length of color in Management UI.
|
||||||
|
*/
|
||||||
|
int COLOUR_MAX_SIZE = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return immutable set of optional {@link DistributionSetType}s
|
||||||
|
*/
|
||||||
|
Set<DistributionSetType> getCompatibleDistributionSetTypes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return immutable set of optional {@link Target}s
|
||||||
|
*/
|
||||||
|
Set<Target> getTargets();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given {@link DistributionSetType} is in
|
||||||
|
* {@link #getCompatibleDistributionSetTypes()}.
|
||||||
|
*
|
||||||
|
* @param distributionSetType
|
||||||
|
* search for
|
||||||
|
* @return <code>true</code> if found
|
||||||
|
*/
|
||||||
|
default boolean containsCompatibleDistributionSetType(final DistributionSetType distributionSetType) {
|
||||||
|
return containsCompatibleDistributionSetType(distributionSetType.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given {@link DistributionSetType} is in
|
||||||
|
* {@link #getCompatibleDistributionSetTypes()}.
|
||||||
|
*
|
||||||
|
* @param distributionSetTypeId
|
||||||
|
* search by {@link DistributionSetType#getId()}
|
||||||
|
* @return <code>true</code> if found
|
||||||
|
*/
|
||||||
|
default boolean containsCompatibleDistributionSetType(final Long distributionSetTypeId) {
|
||||||
|
return getCompatibleDistributionSetTypes().stream().anyMatch(element -> element.getId().equals(distributionSetTypeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unassigns a distribution set type from target types
|
||||||
|
* @param dsTypeId
|
||||||
|
* @return the resulting target type
|
||||||
|
*/
|
||||||
|
TargetType removeDistributionSetType(final Long dsTypeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return get color code to be used in management UI views.
|
||||||
|
*/
|
||||||
|
String getColour();
|
||||||
|
}
|
||||||
@@ -108,4 +108,8 @@ public class PropertiesQuotaManagement implements QuotaManagement {
|
|||||||
return securityProperties.getDos().getMaxArtifactStorage();
|
return securityProperties.getDos().getMaxArtifactStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxDistributionSetTypesPerTargetType() {
|
||||||
|
return securityProperties.getDos().getMaxDistributionSetTypesPerTargetType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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.builder;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.ValidString;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and update builder DTO.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* update or create builder interface
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTargetTypeUpdateCreate<T> extends AbstractNamedEntityBuilder<T> {
|
||||||
|
@ValidString
|
||||||
|
protected String colour;
|
||||||
|
|
||||||
|
protected Collection<Long> compatible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param compatible
|
||||||
|
* list of ID
|
||||||
|
* @return generic type
|
||||||
|
*/
|
||||||
|
public T compatible(final Collection<Long> compatible) {
|
||||||
|
this.compatible = compatible;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of ID
|
||||||
|
*/
|
||||||
|
public Optional<Collection<Long>> getCompatible() {
|
||||||
|
return Optional.ofNullable(compatible);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param colour
|
||||||
|
* Colour value
|
||||||
|
* @return generic type
|
||||||
|
*/
|
||||||
|
public T colour(final String colour) {
|
||||||
|
this.colour = StringUtils.trimWhitespace(colour);
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return colour
|
||||||
|
*/
|
||||||
|
public Optional<String> getColour() {
|
||||||
|
return Optional.ofNullable(colour);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,8 +11,11 @@ package org.eclipse.hawkbit.repository.builder;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||||
import org.eclipse.hawkbit.repository.ValidString;
|
import org.eclipse.hawkbit.repository.ValidString;
|
||||||
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
|
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -36,6 +39,8 @@ public class AbstractTargetUpdateCreate<T> extends AbstractNamedEntityBuilder<T>
|
|||||||
|
|
||||||
protected Boolean requestAttributes;
|
protected Boolean requestAttributes;
|
||||||
|
|
||||||
|
protected Long targetTypeId;
|
||||||
|
|
||||||
protected AbstractTargetUpdateCreate(final String controllerId) {
|
protected AbstractTargetUpdateCreate(final String controllerId) {
|
||||||
this.controllerId = StringUtils.trimWhitespace(controllerId);
|
this.controllerId = StringUtils.trimWhitespace(controllerId);
|
||||||
}
|
}
|
||||||
@@ -79,6 +84,11 @@ public class AbstractTargetUpdateCreate<T> extends AbstractNamedEntityBuilder<T>
|
|||||||
return (TargetCreate) this;
|
return (TargetCreate) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T targetType(final Long targetTypeId) {
|
||||||
|
this.targetTypeId = targetTypeId;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
public String getControllerId() {
|
public String getControllerId() {
|
||||||
return controllerId;
|
return controllerId;
|
||||||
}
|
}
|
||||||
@@ -99,4 +109,8 @@ public class AbstractTargetUpdateCreate<T> extends AbstractNamedEntityBuilder<T>
|
|||||||
return Optional.ofNullable(status);
|
return Optional.ofNullable(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getTargetTypeId() {
|
||||||
|
return targetTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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.builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update implementation.
|
||||||
|
*/
|
||||||
|
public class GenericTargetTypeUpdate extends AbstractTargetTypeUpdateCreate<TargetTypeUpdate>
|
||||||
|
implements TargetTypeUpdate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* Target type ID
|
||||||
|
*/
|
||||||
|
public GenericTargetTypeUpdate(final Long id) {
|
||||||
|
super.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.configuration.Constants;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
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.rsql.RSQLUtility;
|
||||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification;
|
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification;
|
||||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||||
@@ -66,6 +67,8 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
|
|
||||||
private final DistributionSetRepository distributionSetRepository;
|
private final DistributionSetRepository distributionSetRepository;
|
||||||
|
|
||||||
|
private final TargetTypeRepository targetTypeRepository;
|
||||||
|
|
||||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||||
|
|
||||||
private final Database database;
|
private final Database database;
|
||||||
@@ -74,12 +77,13 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
|
|
||||||
JpaDistributionSetTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
|
JpaDistributionSetTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||||
final DistributionSetRepository distributionSetRepository,
|
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
|
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
|
||||||
final QuotaManagement quotaManagement) {
|
final QuotaManagement quotaManagement) {
|
||||||
this.distributionSetTypeRepository = distributionSetTypeRepository;
|
this.distributionSetTypeRepository = distributionSetTypeRepository;
|
||||||
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
||||||
this.distributionSetRepository = distributionSetRepository;
|
this.distributionSetRepository = distributionSetRepository;
|
||||||
|
this.targetTypeRepository = targetTypeRepository;
|
||||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||||
this.database = database;
|
this.database = database;
|
||||||
this.quotaManagement = quotaManagement;
|
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}.
|
* {@link SoftwareModuleType}s per {@link DistributionSetType}.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
@@ -268,18 +272,28 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
|||||||
@Retryable(include = {
|
@Retryable(include = {
|
||||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public void delete(final long typeId) {
|
public void delete(final long typeId) {
|
||||||
|
|
||||||
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(typeId)
|
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(typeId)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, typeId));
|
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, typeId));
|
||||||
|
|
||||||
|
unassignDsTypeFromTargetTypes(typeId);
|
||||||
|
|
||||||
if (distributionSetRepository.countByTypeId(typeId) > 0) {
|
if (distributionSetRepository.countByTypeId(typeId) > 0) {
|
||||||
toDelete.setDeleted(true);
|
toDelete.setDeleted(true);
|
||||||
distributionSetTypeRepository.save(toDelete);
|
distributionSetTypeRepository.save(toDelete);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
distributionSetTypeRepository.deleteById(typeId);
|
distributionSetTypeRepository.deleteById(typeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void unassignDsTypeFromTargetTypes(long typeId) {
|
||||||
|
List<JpaTargetType> targetTypesByDsType = targetTypeRepository.findByDsType(typeId);
|
||||||
|
targetTypesByDsType.forEach(targetType -> {
|
||||||
|
targetType.removeDistributionSetType(typeId);
|
||||||
|
targetTypeRepository.save(targetType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retryable(include = {
|
@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.TagBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
import org.eclipse.hawkbit.repository.builder.TargetBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
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.JpaActionStatusBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeBuilder;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeBuilder;
|
||||||
@@ -42,6 +43,9 @@ public class JpaEntityFactory implements EntityFactory {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DistributionSetBuilder distributionSetBuilder;
|
private DistributionSetBuilder distributionSetBuilder;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TargetBuilder targetBuilder;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DistributionSetTypeBuilder distributionSetTypeBuilder;
|
private DistributionSetTypeBuilder distributionSetTypeBuilder;
|
||||||
|
|
||||||
@@ -57,6 +61,9 @@ public class JpaEntityFactory implements EntityFactory {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder;
|
private SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TargetTypeBuilder targetTypeBuilder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MetaData generateDsMetadata(final String key, final String value) {
|
public MetaData generateDsMetadata(final String key, final String value) {
|
||||||
return new JpaDistributionSetMetadata(key, StringUtils.trimWhitespace(value));
|
return new JpaDistributionSetMetadata(key, StringUtils.trimWhitespace(value));
|
||||||
@@ -79,7 +86,12 @@ public class JpaEntityFactory implements EntityFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetBuilder target() {
|
public TargetBuilder target() {
|
||||||
return new JpaTargetBuilder();
|
return targetBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TargetTypeBuilder targetType() {
|
||||||
|
return targetTypeBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.configuration.MultiTenantJpaTransactionManager;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
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.model.JpaTenantMetaData;
|
||||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
@@ -93,6 +94,9 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TargetTagRepository targetTagRepository;
|
private TargetTagRepository targetTagRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TargetTypeRepository targetTypeRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DistributionSetTagRepository distributionSetTagRepository;
|
private DistributionSetTagRepository distributionSetTagRepository;
|
||||||
|
|
||||||
@@ -255,6 +259,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
targetRepository.deleteByTenant(tenant);
|
targetRepository.deleteByTenant(tenant);
|
||||||
targetFilterQueryRepository.deleteByTenant(tenant);
|
targetFilterQueryRepository.deleteByTenant(tenant);
|
||||||
rolloutRepository.deleteByTenant(tenant);
|
rolloutRepository.deleteByTenant(tenant);
|
||||||
|
targetTypeRepository.deleteByTenant(tenant);
|
||||||
targetTagRepository.deleteByTenant(tenant);
|
targetTagRepository.deleteByTenant(tenant);
|
||||||
distributionSetTagRepository.deleteByTenant(tenant);
|
distributionSetTagRepository.deleteByTenant(tenant);
|
||||||
distributionSetRepository.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.JpaTargetMetadata_;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata_;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
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.JpaTarget_;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
||||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
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.TargetMetadata;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
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.TargetUpdateStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||||
@@ -98,6 +100,8 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
|
|
||||||
private final TargetRepository targetRepository;
|
private final TargetRepository targetRepository;
|
||||||
|
|
||||||
|
private final TargetTypeRepository targetTypeRepository;
|
||||||
|
|
||||||
private final TargetMetadataRepository targetMetadataRepository;
|
private final TargetMetadataRepository targetMetadataRepository;
|
||||||
|
|
||||||
private final RolloutGroupRepository rolloutGroupRepository;
|
private final RolloutGroupRepository rolloutGroupRepository;
|
||||||
@@ -119,7 +123,7 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
private final Database database;
|
private final Database database;
|
||||||
|
|
||||||
public JpaTargetManagement(final EntityManager entityManager, final QuotaManagement quotaManagement,
|
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 RolloutGroupRepository rolloutGroupRepository,
|
||||||
final DistributionSetRepository distributionSetRepository,
|
final DistributionSetRepository distributionSetRepository,
|
||||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||||
@@ -130,6 +134,7 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
this.quotaManagement = quotaManagement;
|
this.quotaManagement = quotaManagement;
|
||||||
this.targetRepository = targetRepository;
|
this.targetRepository = targetRepository;
|
||||||
|
this.targetTypeRepository = targetTypeRepository;
|
||||||
this.targetMetadataRepository = targetMetadataRepository;
|
this.targetMetadataRepository = targetMetadataRepository;
|
||||||
this.rolloutGroupRepository = rolloutGroupRepository;
|
this.rolloutGroupRepository = rolloutGroupRepository;
|
||||||
this.distributionSetRepository = distributionSetRepository;
|
this.distributionSetRepository = distributionSetRepository;
|
||||||
@@ -152,6 +157,10 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JpaTargetType getTargetTypeByIdAndThrowIfNotFound(final long id) {
|
||||||
|
return targetTypeRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(TargetType.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Target> getByControllerID(final Collection<String> controllerIDs) {
|
public List<Target> getByControllerID(final Collection<String> controllerIDs) {
|
||||||
return Collections.unmodifiableList(
|
return Collections.unmodifiableList(
|
||||||
@@ -333,6 +342,10 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
update.getDescription().ifPresent(target::setDescription);
|
update.getDescription().ifPresent(target::setDescription);
|
||||||
update.getAddress().ifPresent(target::setAddress);
|
update.getAddress().ifPresent(target::setAddress);
|
||||||
update.getSecurityToken().ifPresent(target::setSecurityToken);
|
update.getSecurityToken().ifPresent(target::setSecurityToken);
|
||||||
|
if (update.getTargetTypeId() != null){
|
||||||
|
TargetType targetType = getTargetTypeByIdAndThrowIfNotFound(update.getTargetTypeId());
|
||||||
|
target.setTargetType(targetType);
|
||||||
|
}
|
||||||
|
|
||||||
return targetRepository.save(target);
|
return targetRepository.save(target);
|
||||||
}
|
}
|
||||||
@@ -589,6 +602,24 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
return result;
|
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
|
@Override
|
||||||
public Slice<Target> findByFilterOrderByLinkedDistributionSet(final Pageable pageable,
|
public Slice<Target> findByFilterOrderByLinkedDistributionSet(final Pageable pageable,
|
||||||
final long orderByDistributionId, final FilterParams filterParams) {
|
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.TargetFilterQueryManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
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.RolloutBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
|
import org.eclipse.hawkbit.repository.builder.SoftwareModuleBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataBuilder;
|
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.TargetFilterQueryBuilder;
|
||||||
|
import org.eclipse.hawkbit.repository.builder.TargetTypeBuilder;
|
||||||
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
|
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
|
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.EventEntityManagerHolder;
|
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.JpaRolloutBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleBuilder;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataBuilder;
|
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.JpaTargetFilterQueryBuilder;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetTypeBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
|
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
|
||||||
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
||||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitDefaultServiceExecutor;
|
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.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
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.EventPublisherHolder;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||||
@@ -231,6 +237,21 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
return new JpaDistributionSetBuilder(distributionSetTypeManagement, softwareManagement);
|
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
|
@Bean
|
||||||
SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder(
|
SoftwareModuleMetadataBuilder softwareModuleMetadataBuilder(
|
||||||
final SoftwareModuleManagement softwareModuleManagement) {
|
final SoftwareModuleManagement softwareModuleManagement) {
|
||||||
@@ -465,10 +486,26 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||||
final DistributionSetRepository distributionSetRepository,
|
final DistributionSetRepository distributionSetRepository,
|
||||||
|
final TargetTypeRepository targetTypeRepository,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
|
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
|
||||||
final QuotaManagement quotaManagement) {
|
final QuotaManagement quotaManagement) {
|
||||||
return new JpaDistributionSetTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
|
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 TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||||
final RolloutGroupRepository rolloutGroupRepository,
|
final RolloutGroupRepository rolloutGroupRepository,
|
||||||
final DistributionSetRepository distributionSetRepository,
|
final DistributionSetRepository distributionSetRepository,
|
||||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetTypeRepository targetTypeRepository,
|
||||||
final TargetTagRepository targetTagRepository, final EventPublisherHolder eventPublisherHolder,
|
final TargetTagRepository targetTagRepository, final EventPublisherHolder eventPublisherHolder,
|
||||||
final TenantAware tenantAware, final AfterTransactionCommitExecutor afterCommit,
|
final TenantAware tenantAware, final AfterTransactionCommitExecutor afterCommit,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
|
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,
|
rolloutGroupRepository, distributionSetRepository, targetFilterQueryRepository, targetTagRepository,
|
||||||
eventPublisherHolder, tenantAware, afterCommit, virtualPropertyReplacer, properties.getDatabase());
|
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.model.JpaTarget;
|
||||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
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.TargetUpdateStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -200,6 +201,15 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
|||||||
return this.count(Specification.where(null));
|
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
|
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
* 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;
|
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.TargetBuilder;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder implementation for {@link Target}.
|
* Builder implementation for {@link Target}.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class JpaTargetBuilder implements TargetBuilder {
|
public class JpaTargetBuilder implements TargetBuilder {
|
||||||
|
final private TargetTypeManagement targetTypeManagement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetTypeManagement
|
||||||
|
* Target type management
|
||||||
|
*/
|
||||||
|
public JpaTargetBuilder(TargetTypeManagement targetTypeManagement) {
|
||||||
|
this.targetTypeManagement = targetTypeManagement;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetUpdate update(final String controllerId) {
|
public TargetUpdate update(final String controllerId) {
|
||||||
@@ -25,7 +36,7 @@ public class JpaTargetBuilder implements TargetBuilder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetCreate create() {
|
public TargetCreate create() {
|
||||||
return new JpaTargetCreate();
|
return new JpaTargetCreate(targetTypeManagement);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
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.AbstractTargetUpdateCreate;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
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.jpa.model.JpaTarget;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -20,8 +23,17 @@ import org.springframework.util.StringUtils;
|
|||||||
*/
|
*/
|
||||||
public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> implements TargetCreate {
|
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);
|
super(null);
|
||||||
|
this.targetTypeManagement = targetTypeManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -38,6 +50,12 @@ public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> im
|
|||||||
target.setName(name);
|
target.setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetTypeId != null){
|
||||||
|
TargetType targetType = targetTypeManagement.get(targetTypeId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId));
|
||||||
|
target.setTargetType(targetType);
|
||||||
|
}
|
||||||
|
|
||||||
target.setDescription(description);
|
target.setDescription(description);
|
||||||
target.setAddress(address);
|
target.setAddress(address);
|
||||||
target.setUpdateStatus(getStatus().orElse(TargetUpdateStatus.UNKNOWN));
|
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;
|
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.DistributionSetTypeDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeUpdatedEvent;
|
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.DistributionSetType;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
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.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||||
import org.springframework.util.CollectionUtils;
|
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
|
* A distribution set type defines which software module types can or have to be
|
||||||
* {@link DistributionSet}.
|
* {@link DistributionSet}.
|
||||||
@@ -72,6 +73,10 @@ public class JpaDistributionSetType extends AbstractJpaNamedEntity implements Di
|
|||||||
@Column(name = "deleted")
|
@Column(name = "deleted")
|
||||||
private boolean deleted;
|
private boolean deleted;
|
||||||
|
|
||||||
|
@CascadeOnDelete
|
||||||
|
@ManyToMany(mappedBy = "distributionSetTypes", targetEntity = JpaTargetType.class, fetch = FetchType.LAZY)
|
||||||
|
private List<TargetType> compatibleToTargetTypes;
|
||||||
|
|
||||||
public JpaDistributionSetType() {
|
public JpaDistributionSetType() {
|
||||||
// default public constructor for JPA
|
// 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.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
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.TargetUpdateStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
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"))
|
@JoinColumn(name = "target_id", nullable = false, updatable = false) }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
|
||||||
private Map<String, String> controllerAttributes;
|
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
|
// set default request controller attributes to true, because we want to
|
||||||
// request them the first
|
// request them the first
|
||||||
// time
|
// time
|
||||||
@@ -201,10 +206,16 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
: controllerId;
|
: controllerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
JpaTarget() {
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public JpaTarget() {
|
||||||
// empty constructor for JPA.
|
// empty constructor for JPA.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return assigned distribution set
|
||||||
|
*/
|
||||||
public DistributionSet getAssignedDistributionSet() {
|
public DistributionSet getAssignedDistributionSet() {
|
||||||
return assignedDistributionSet;
|
return assignedDistributionSet;
|
||||||
}
|
}
|
||||||
@@ -214,6 +225,9 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return controllerId;
|
return controllerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return tags
|
||||||
|
*/
|
||||||
public Set<TargetTag> getTags() {
|
public Set<TargetTag> getTags() {
|
||||||
if (tags == null) {
|
if (tags == null) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
@@ -222,6 +236,9 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return Collections.unmodifiableSet(tags);
|
return Collections.unmodifiableSet(tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return rollouts target group
|
||||||
|
*/
|
||||||
public List<RolloutTargetGroup> getRolloutTargetGroup() {
|
public List<RolloutTargetGroup> getRolloutTargetGroup() {
|
||||||
if (rolloutTargetGroup == null) {
|
if (rolloutTargetGroup == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@@ -230,6 +247,11 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return Collections.unmodifiableList(rolloutTargetGroup);
|
return Collections.unmodifiableList(rolloutTargetGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag
|
||||||
|
* tag
|
||||||
|
* @return boolean true or false
|
||||||
|
*/
|
||||||
public boolean addTag(final TargetTag tag) {
|
public boolean addTag(final TargetTag tag) {
|
||||||
if (tags == null) {
|
if (tags == null) {
|
||||||
tags = new HashSet<>();
|
tags = new HashSet<>();
|
||||||
@@ -238,6 +260,11 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return tags.add(tag);
|
return tags.add(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag
|
||||||
|
* tag
|
||||||
|
* @return boolean true or false
|
||||||
|
*/
|
||||||
public boolean removeTag(final TargetTag tag) {
|
public boolean removeTag(final TargetTag tag) {
|
||||||
if (tags == null) {
|
if (tags == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -246,14 +273,25 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return tags.remove(tag);
|
return tags.remove(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param assignedDistributionSet
|
||||||
|
* Distribution set
|
||||||
|
*/
|
||||||
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
|
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
|
||||||
this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet;
|
this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param controllerId
|
||||||
|
* Controller ID
|
||||||
|
*/
|
||||||
public void setControllerId(final String controllerId) {
|
public void setControllerId(final String controllerId) {
|
||||||
this.controllerId = controllerId;
|
this.controllerId = controllerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list of action
|
||||||
|
*/
|
||||||
public List<Action> getActions() {
|
public List<Action> getActions() {
|
||||||
if (actions == null) {
|
if (actions == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@@ -262,6 +300,11 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return Collections.unmodifiableList(actions);
|
return Collections.unmodifiableList(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param action
|
||||||
|
* Action
|
||||||
|
* @return boolean true or false
|
||||||
|
*/
|
||||||
public boolean addAction(final Action action) {
|
public boolean addAction(final Action action) {
|
||||||
if (actions == null) {
|
if (actions == null) {
|
||||||
actions = new ArrayList<>();
|
actions = new ArrayList<>();
|
||||||
@@ -285,6 +328,10 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param securityToken
|
||||||
|
* token value
|
||||||
|
*/
|
||||||
public void setSecurityToken(final String securityToken) {
|
public void setSecurityToken(final String securityToken) {
|
||||||
this.securityToken = securityToken;
|
this.securityToken = securityToken;
|
||||||
}
|
}
|
||||||
@@ -348,10 +395,29 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return updateStatus;
|
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() {
|
public JpaDistributionSet getInstalledDistributionSet() {
|
||||||
return installedDistributionSet;
|
return installedDistributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return controller attributes
|
||||||
|
*/
|
||||||
public Map<String, String> getControllerAttributes() {
|
public Map<String, String> getControllerAttributes() {
|
||||||
return controllerAttributes;
|
return controllerAttributes;
|
||||||
}
|
}
|
||||||
@@ -361,6 +427,9 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
return requestControllerAttributes;
|
return requestControllerAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return target metadata
|
||||||
|
*/
|
||||||
public List<TargetMetadata> getMetadata() {
|
public List<TargetMetadata> getMetadata() {
|
||||||
if (metadata == null) {
|
if (metadata == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@@ -375,26 +444,50 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
|||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param address
|
||||||
|
* Address
|
||||||
|
*/
|
||||||
public void setAddress(final String address) {
|
public void setAddress(final String address) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param lastTargetQuery
|
||||||
|
* last query ID
|
||||||
|
*/
|
||||||
public void setLastTargetQuery(final Long lastTargetQuery) {
|
public void setLastTargetQuery(final Long lastTargetQuery) {
|
||||||
this.lastTargetQuery = lastTargetQuery;
|
this.lastTargetQuery = lastTargetQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param installationDate
|
||||||
|
* installation date
|
||||||
|
*/
|
||||||
public void setInstallationDate(final Long installationDate) {
|
public void setInstallationDate(final Long installationDate) {
|
||||||
this.installationDate = installationDate;
|
this.installationDate = installationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param installedDistributionSet
|
||||||
|
* Distribution set
|
||||||
|
*/
|
||||||
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
|
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
|
||||||
this.installedDistributionSet = installedDistributionSet;
|
this.installedDistributionSet = installedDistributionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param updateStatus
|
||||||
|
* Status
|
||||||
|
*/
|
||||||
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
|
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
|
||||||
this.updateStatus = updateStatus;
|
this.updateStatus = updateStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param requestControllerAttributes
|
||||||
|
* Attributes
|
||||||
|
*/
|
||||||
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
|
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
|
||||||
this.requestControllerAttributes = 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
|
@Autowired
|
||||||
protected TargetTagRepository targetTagRepository;
|
protected TargetTagRepository targetTagRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected TargetTypeRepository targetTypeRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected DistributionSetTagRepository distributionSetTagRepository;
|
protected DistributionSetTagRepository distributionSetTagRepository;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.validation.ConstraintViolationException;
|
import javax.validation.ConstraintViolationException;
|
||||||
@@ -27,6 +28,7 @@ import javax.validation.ConstraintViolationException;
|
|||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||||
import org.eclipse.hawkbit.repository.FilterParams;
|
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.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
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.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
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.Expect;
|
||||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||||
@@ -1038,6 +1041,67 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
assertThat(updated.getTarget().getId()).isEqualTo(target.getId());
|
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
|
@Test
|
||||||
@Description("Queries and loads the metadata related to a given target.")
|
@Description("Queries and loads the metadata related to a given target.")
|
||||||
public void findAllTargetMetadataByControllerId() {
|
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 static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
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.RolloutDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
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.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
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.SoftwareModuleUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
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.event.remote.entity.TargetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||||
import org.eclipse.hawkbit.repository.jpa.event.RepositoryEntityEventTest.RepositoryTestConfiguration;
|
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.Rollout;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
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.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -88,6 +93,38 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
|
|||||||
assertThat(targetDeletedEvent.getEntityId()).isEqualTo(createdTarget.getId());
|
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
|
@Test
|
||||||
@Description("Verifies that the rollout deleted event is published when a rollout has been deleted")
|
@Description("Verifies that the rollout deleted event is published when a rollout has been deleted")
|
||||||
public void rolloutDeletedEventIsPublished() throws InterruptedException {
|
public void rolloutDeletedEventIsPublished() throws InterruptedException {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import org.eclipse.hawkbit.repository.SystemManagement;
|
|||||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||||
@@ -144,6 +145,9 @@ public abstract class AbstractIntegrationTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
protected TargetManagement targetManagement;
|
protected TargetManagement targetManagement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected TargetTypeManagement targetTypeManagement;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected TargetFilterQueryManagement targetFilterQueryManagement;
|
protected TargetFilterQueryManagement targetFilterQueryManagement;
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class JpaTestRepositoryManagement {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOGGER.error("Error hile delete tenant", e);
|
LOGGER.error("Error while delete tenant", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,10 @@ import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
|||||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||||
|
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||||
@@ -61,6 +63,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
|||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
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.TargetUpdateStatus;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
@@ -123,6 +126,8 @@ public class TestdataFactory {
|
|||||||
*/
|
*/
|
||||||
public static final String SM_TYPE_APP = "application";
|
public static final String SM_TYPE_APP = "application";
|
||||||
|
|
||||||
|
public static final String DEFAULT_COLOUR = "#000000";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ControllerManagement controllerManagament;
|
private ControllerManagement controllerManagament;
|
||||||
|
|
||||||
@@ -141,6 +146,9 @@ public class TestdataFactory {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TargetManagement targetManagement;
|
private TargetManagement targetManagement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TargetTypeManagement targetTypeManagement;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DeploymentManagement deploymentManagement;
|
private DeploymentManagement deploymentManagement;
|
||||||
|
|
||||||
@@ -638,6 +646,22 @@ public class TestdataFactory {
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param controllerId
|
||||||
|
* of the target
|
||||||
|
* @param targetName
|
||||||
|
* name of the target
|
||||||
|
* @param targetTypeId
|
||||||
|
* target type id
|
||||||
|
* @return persisted {@link Target}
|
||||||
|
*/
|
||||||
|
public Target createTarget(final String controllerId, final String targetName, final Long targetTypeId) {
|
||||||
|
final Target target = targetManagement
|
||||||
|
.create(entityFactory.target().create().controllerId(controllerId).name(targetName).targetType(targetTypeId));
|
||||||
|
assertTargetProperlyCreated(target);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
private void assertTargetProperlyCreated(final Target target) {
|
private void assertTargetProperlyCreated(final Target target) {
|
||||||
assertThat(target.getCreatedBy()).isNotNull();
|
assertThat(target.getCreatedBy()).isNotNull();
|
||||||
assertThat(target.getCreatedAt()).isNotNull();
|
assertThat(target.getCreatedAt()).isNotNull();
|
||||||
@@ -1160,4 +1184,54 @@ public class TestdataFactory {
|
|||||||
rolloutManagement.handleRollouts();
|
rolloutManagement.handleRollouts();
|
||||||
return newRollout;
|
return newRollout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds {@link TargetType} in repository with given
|
||||||
|
* {@link TargetType#getName()} or creates if it does not exist yet.
|
||||||
|
* No ds types are assigned on creation.
|
||||||
|
*
|
||||||
|
* @param targetTypeName
|
||||||
|
* {@link TargetType#getName()}
|
||||||
|
*
|
||||||
|
* @return persisted {@link TargetType}
|
||||||
|
*/
|
||||||
|
public TargetType findOrCreateTargetType(final String targetTypeName) {
|
||||||
|
return targetTypeManagement.getByName(targetTypeName)
|
||||||
|
.orElseGet(() -> targetTypeManagement.create(entityFactory.targetType().create()
|
||||||
|
.name(targetTypeName).description(targetTypeName + " description").colour(DEFAULT_COLOUR)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link TargetType} in repository with given
|
||||||
|
* {@link TargetType#getName()}. Compatible distribution set types are assigned on creation
|
||||||
|
*
|
||||||
|
* @param targetTypeName
|
||||||
|
* {@link TargetType#getName()}
|
||||||
|
*
|
||||||
|
* @return persisted {@link TargetType}
|
||||||
|
*/
|
||||||
|
public TargetType createTargetType(final String targetTypeName, List<DistributionSetType> compatibleDsTypes) {
|
||||||
|
return targetTypeManagement.create(entityFactory.targetType().create()
|
||||||
|
.name(targetTypeName).description(targetTypeName + " description").colour(DEFAULT_COLOUR)
|
||||||
|
.compatible(compatibleDsTypes.stream().map(DistributionSetType::getId).collect(Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link TargetType} in repository with given
|
||||||
|
* {@link TargetType#getName()}. No ds types are assigned on creation.
|
||||||
|
*
|
||||||
|
* @param targetTypePrefix
|
||||||
|
* {@link TargetType#getName()}
|
||||||
|
*
|
||||||
|
* @return persisted {@link TargetType}
|
||||||
|
*/
|
||||||
|
public List<TargetType> createTargetTypes(final String targetTypePrefix, int count) {
|
||||||
|
final List<TargetTypeCreate> result = Lists.newArrayListWithExpectedSize(count);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
result.add(entityFactory.targetType().create().name(targetTypePrefix + i).description(targetTypePrefix + " description")
|
||||||
|
.colour(DEFAULT_COLOUR));
|
||||||
|
}
|
||||||
|
return targetTypeManagement.create(result);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.json.model.distributionsettype;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request Body of DistributionSetType for assignment operations (ID only).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class MgmtDistributionSetTypeAssignment extends MgmtId {
|
||||||
|
}
|
||||||
@@ -49,6 +49,24 @@ public class MgmtTarget extends MgmtNamedEntity {
|
|||||||
@JsonProperty
|
@JsonProperty
|
||||||
private boolean requestAttributes;
|
private boolean requestAttributes;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private Long targetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Target type ID
|
||||||
|
*/
|
||||||
|
public Long getTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetType
|
||||||
|
* Target type ID
|
||||||
|
*/
|
||||||
|
public void setTargetType(Long targetType) {
|
||||||
|
this.targetType = targetType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the controllerId
|
* @return the controllerId
|
||||||
*/
|
*/
|
||||||
@@ -150,6 +168,9 @@ public class MgmtTarget extends MgmtNamedEntity {
|
|||||||
return securityToken;
|
return securityToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Address
|
||||||
|
*/
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
@@ -171,6 +192,9 @@ public class MgmtTarget extends MgmtNamedEntity {
|
|||||||
this.securityToken = securityToken;
|
this.securityToken = securityToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return boolean true or false
|
||||||
|
*/
|
||||||
public boolean isRequestAttributes() {
|
public boolean isRequestAttributes() {
|
||||||
return requestAttributes;
|
return requestAttributes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,34 @@ public class MgmtTargetRequestBody {
|
|||||||
@JsonProperty
|
@JsonProperty
|
||||||
private Boolean requestAttributes;
|
private Boolean requestAttributes;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private Long targetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Target type ID
|
||||||
|
*/
|
||||||
|
public Long getTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param targetType
|
||||||
|
* Target type ID
|
||||||
|
*/
|
||||||
|
public void setTargetType(Long targetType) {
|
||||||
|
this.targetType = targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return token
|
||||||
|
*/
|
||||||
public String getSecurityToken() {
|
public String getSecurityToken() {
|
||||||
return securityToken;
|
return securityToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param securityToken Token
|
||||||
|
*/
|
||||||
public void setSecurityToken(final String securityToken) {
|
public void setSecurityToken(final String securityToken) {
|
||||||
this.securityToken = securityToken;
|
this.securityToken = securityToken;
|
||||||
}
|
}
|
||||||
@@ -83,18 +107,32 @@ public class MgmtTargetRequestBody {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return address
|
||||||
|
*/
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param address
|
||||||
|
* Address
|
||||||
|
*/
|
||||||
public void setAddress(final String address) {
|
public void setAddress(final String address) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return boolean true or false
|
||||||
|
*/
|
||||||
public Boolean isRequestAttributes() {
|
public Boolean isRequestAttributes() {
|
||||||
return requestAttributes;
|
return requestAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param requestAttributes
|
||||||
|
* Attributes
|
||||||
|
*/
|
||||||
public void setRequestAttributes(final Boolean requestAttributes) {
|
public void setRequestAttributes(final Boolean requestAttributes) {
|
||||||
this.requestAttributes = requestAttributes;
|
this.requestAttributes = requestAttributes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.json.model.targettype;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A json annotated rest model for TargetType to RESTful API
|
||||||
|
* representation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class MgmtTargetType extends MgmtNamedEntity {
|
||||||
|
|
||||||
|
@JsonProperty(value = "id", required = true)
|
||||||
|
private Long typeId;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String colour;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return target type ID
|
||||||
|
*/
|
||||||
|
public Long getTypeId() {
|
||||||
|
return typeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param typeId
|
||||||
|
* Target type ID
|
||||||
|
*/
|
||||||
|
public void setTypeId(final Long typeId) {
|
||||||
|
this.typeId = typeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the color in format #000000
|
||||||
|
*/
|
||||||
|
public String getColour() {
|
||||||
|
return colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param colour
|
||||||
|
* in format #000000
|
||||||
|
*/
|
||||||
|
public void setColour(String colour) {
|
||||||
|
this.colour = colour;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.json.model.targettype;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeAssigment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request Body for TargetType POST.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MgmtTargetTypeRequestBodyPost extends MgmtTargetTypeRequestBodyPut{
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private List<MgmtDistributionSetTypeAssignment> compatibledistributionsettypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* the name to set
|
||||||
|
* @return post request body
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MgmtTargetTypeRequestBodyPost setName(final String name) {
|
||||||
|
super.setName(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MgmtTargetTypeRequestBodyPost setDescription(final String description) {
|
||||||
|
super.setDescription(description);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MgmtTargetTypeRequestBodyPost setColour(final String colour) {
|
||||||
|
super.setColour(colour);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the compatible ds types
|
||||||
|
*/
|
||||||
|
public List<MgmtDistributionSetTypeAssignment> getCompatibleDsTypes() {
|
||||||
|
return compatibledistributionsettypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param compatibleDsTypes
|
||||||
|
* the compatible ds types to set
|
||||||
|
*
|
||||||
|
* @return updated body
|
||||||
|
*/
|
||||||
|
public MgmtTargetTypeRequestBodyPost setCompatibleDsTypes(
|
||||||
|
final List<MgmtDistributionSetTypeAssignment> compatibleDsTypes) {
|
||||||
|
this.compatibledistributionsettypes = compatibleDsTypes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.json.model.targettype;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request Body for TargetType PUT.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MgmtTargetTypeRequestBodyPut {
|
||||||
|
|
||||||
|
@JsonProperty(required = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String colour;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* the name to set
|
||||||
|
*
|
||||||
|
* @return updated body
|
||||||
|
*/
|
||||||
|
public MgmtTargetTypeRequestBodyPut setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return description
|
||||||
|
*/
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param description
|
||||||
|
* Description
|
||||||
|
* @return Updated body
|
||||||
|
*/
|
||||||
|
public MgmtTargetTypeRequestBodyPut setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Colour
|
||||||
|
*/
|
||||||
|
public String getColour() {
|
||||||
|
return colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param colour
|
||||||
|
* Colour
|
||||||
|
* @return Updated body
|
||||||
|
*/
|
||||||
|
public MgmtTargetTypeRequestBodyPut setColour(final String colour) {
|
||||||
|
this.colour = colour;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,11 @@ public final class MgmtRestConstants {
|
|||||||
|
|
||||||
public static final String SYSTEM_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + BASE_SYSTEM_MAPPING;
|
public static final String SYSTEM_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + BASE_SYSTEM_MAPPING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target URL mapping, href link for assigned target type.
|
||||||
|
*/
|
||||||
|
public static final String TARGET_V1_ASSIGNED_TARGET_TYPE= "targetType";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The target URL mapping, href link for assigned distribution set.
|
* The target URL mapping, href link for assigned distribution set.
|
||||||
*/
|
*/
|
||||||
@@ -99,6 +104,21 @@ public final class MgmtRestConstants {
|
|||||||
*/
|
*/
|
||||||
public static final String TARGET_TAG_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targettags";
|
public static final String TARGET_TAG_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targettags";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target URL mapping rest resource.
|
||||||
|
*/
|
||||||
|
public static final String TARGET_TARGET_TYPE_V1_REQUEST_MAPPING = "/{targetId}/targettype";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target type URL mapping rest resource.
|
||||||
|
*/
|
||||||
|
public static final String TARGETTYPE_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targettypes";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target type URL mapping rest resource.
|
||||||
|
*/
|
||||||
|
public static final String TARGETTYPE_V1_DS_TYPES = "compatibledistributionsettypes";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tag URL mapping rest resource.
|
* The tag URL mapping rest resource.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.mgmt.rest.api;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||||
@@ -123,6 +124,31 @@ public interface MgmtTargetRestApi {
|
|||||||
@DeleteMapping(value = "/{targetId}")
|
@DeleteMapping(value = "/{targetId}")
|
||||||
ResponseEntity<Void> deleteTarget(@PathVariable("targetId") String targetId);
|
ResponseEntity<Void> deleteTarget(@PathVariable("targetId") String targetId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the DELETE (unassign) request of a target type.
|
||||||
|
*
|
||||||
|
* @param targetId
|
||||||
|
* the ID of the target
|
||||||
|
* @return If the given targetId could exists and could be unassign Http OK.
|
||||||
|
* In any failure the JsonResponseExceptionHandler is handling the
|
||||||
|
* response.
|
||||||
|
*/
|
||||||
|
@DeleteMapping(value = MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING)
|
||||||
|
ResponseEntity<Void> unassignTargetType(@PathVariable("targetId") String targetId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the POST (assign) request of a target type.
|
||||||
|
*
|
||||||
|
* @param targetId
|
||||||
|
* the ID of the target
|
||||||
|
* @return If the given targetId could exists and could be assign Http OK.
|
||||||
|
* In any failure the JsonResponseExceptionHandler is handling the
|
||||||
|
* response.
|
||||||
|
*/
|
||||||
|
@PostMapping(value = MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING, consumes = { MediaTypes.HAL_JSON_VALUE,
|
||||||
|
MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<Void> assignTargetType(@PathVariable("targetId") String targetId, MgmtId targetTypeId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the GET request of retrieving the attributes of a specific
|
* Handles the GET request of retrieving the attributes of a specific
|
||||||
* target.
|
* target.
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.rest.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetType;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPost;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPut;
|
||||||
|
import org.springframework.hateoas.MediaTypes;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST Resource handling for TargetType CRUD operations.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RequestMapping(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING)
|
||||||
|
public interface MgmtTargetTypeRestApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the GET request of retrieving all TargetTypes.
|
||||||
|
*
|
||||||
|
* @param pagingOffsetParam
|
||||||
|
* the offset of list of target types for pagination, might not be
|
||||||
|
* present in the rest request then default value will be applied
|
||||||
|
* @param pagingLimitParam
|
||||||
|
* the limit of the paged request, might not be present in the rest
|
||||||
|
* request then default value will be applied
|
||||||
|
* @param sortParam
|
||||||
|
* the sorting parameter in the request URL, syntax
|
||||||
|
* {@code field:direction, field:direction}
|
||||||
|
* @param rsqlParam
|
||||||
|
* the search parameter in the request URL, syntax
|
||||||
|
* {@code q=name==abc}
|
||||||
|
*
|
||||||
|
* @return a list of all TargetTypes for a defined or default page request with
|
||||||
|
* status OK. The response is always paged. In any failure the
|
||||||
|
* JsonResponseExceptionHandler is handling the response.
|
||||||
|
*/
|
||||||
|
@GetMapping(produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<PagedList<MgmtTargetType>> getTargetTypes(
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) int pagingOffsetParam,
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam,
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam,
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the GET request of retrieving a single TargetType.
|
||||||
|
*
|
||||||
|
* @param targetTypeId
|
||||||
|
* the ID of the target type to retrieve
|
||||||
|
*
|
||||||
|
* @return a single target type with status OK.
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/{targetTypeId}", produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<MgmtTargetType> getTargetType(@PathVariable("targetTypeId") Long targetTypeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the DELETE request for a single Target Type.
|
||||||
|
*
|
||||||
|
* @param targetTypeId
|
||||||
|
* the ID of the target type to retrieve
|
||||||
|
* @return status OK if delete is successful.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@DeleteMapping(value = "/{targetTypeId}")
|
||||||
|
ResponseEntity<Void> deleteTargetType(@PathVariable("targetTypeId") Long targetTypeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the PUT request of updating a Target Type.
|
||||||
|
*
|
||||||
|
* @param targetTypeId
|
||||||
|
* the ID of the target type in the URL
|
||||||
|
* @param restTargetType
|
||||||
|
* the target type to be updated.
|
||||||
|
* @return status OK if update is successful
|
||||||
|
*/
|
||||||
|
@PutMapping(value = "/{targetTypeId}", consumes = { MediaTypes.HAL_JSON_VALUE,
|
||||||
|
MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
|
||||||
|
MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<MgmtTargetType> updateTargetType(@PathVariable("targetTypeId") Long targetTypeId,
|
||||||
|
MgmtTargetTypeRequestBodyPut restTargetType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the POST request of creating new Target Types. The request body must
|
||||||
|
* always be a list of types.
|
||||||
|
*
|
||||||
|
* @param targetTypes
|
||||||
|
* the target types to be created.
|
||||||
|
* @return In case all target types could be successfully created the
|
||||||
|
* ResponseEntity with status code 201 - Created but without
|
||||||
|
* ResponseBody. In any failure the JsonResponseExceptionHandler is
|
||||||
|
* handling the response.
|
||||||
|
*/
|
||||||
|
@PostMapping(consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = {
|
||||||
|
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<List<MgmtTargetType>> createTargetTypes(List<MgmtTargetTypeRequestBodyPost> targetTypes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the GET request of retrieving the list of compatible distribution set
|
||||||
|
* types in that target type.
|
||||||
|
*
|
||||||
|
* @param targetTypeId
|
||||||
|
* of the TargetType.
|
||||||
|
* @return Unpaged list of distribution set types and OK in case of success.
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/{targetTypeId}/" + MgmtRestConstants.TARGETTYPE_V1_DS_TYPES, produces = {
|
||||||
|
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<List<MgmtDistributionSetType>> getCompatibleDistributionSets(
|
||||||
|
@PathVariable("targetTypeId") Long targetTypeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles DELETE request for removing the compatibility of a distribution set
|
||||||
|
* type from the target type.
|
||||||
|
*
|
||||||
|
* @param targetTypeId
|
||||||
|
* of the TargetType.
|
||||||
|
* @param distributionSetTypeId
|
||||||
|
* of the DistributionSetType.
|
||||||
|
*
|
||||||
|
* @return OK if the request was successful
|
||||||
|
*/
|
||||||
|
@DeleteMapping(value = "/{targetTypeId}/" + MgmtRestConstants.TARGETTYPE_V1_DS_TYPES + "/{distributionSetTypeId}")
|
||||||
|
ResponseEntity<Void> removeCompatibleDistributionSet(@PathVariable("targetTypeId") Long targetTypeId,
|
||||||
|
@PathVariable("distributionSetTypeId") Long distributionSetTypeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the POST request for adding the compatibility of a distribution set
|
||||||
|
* type to a target type.
|
||||||
|
*
|
||||||
|
* @param targetTypeId
|
||||||
|
* of the TargetType.
|
||||||
|
* @param distributionSetTypeIds
|
||||||
|
* of the DistributionSetTypes as a List.
|
||||||
|
*
|
||||||
|
* @return OK if the request was successful
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/{targetTypeId}/" + MgmtRestConstants.TARGETTYPE_V1_DS_TYPES, consumes = {
|
||||||
|
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<Void> addCompatibleDistributionSets(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||||
|
final List<MgmtDistributionSetTypeAssignment> distributionSetTypeIds);
|
||||||
|
}
|
||||||
@@ -67,7 +67,7 @@ final class MgmtDistributionSetTypeMapper {
|
|||||||
.orElse(Collections.emptyList());
|
.orElse(Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<MgmtDistributionSetType> toListResponse(final List<DistributionSetType> types) {
|
static List<MgmtDistributionSetType> toListResponse(final Collection<DistributionSetType> types) {
|
||||||
if (types == null) {
|
if (types == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
||||||
@@ -30,6 +31,7 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
|||||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
||||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
|
||||||
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||||
import org.eclipse.hawkbit.repository.ActionFields;
|
import org.eclipse.hawkbit.repository.ActionFields;
|
||||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||||
@@ -79,6 +81,10 @@ public final class MgmtTargetMapper {
|
|||||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getMetadata(response.getControllerId(),
|
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getMetadata(response.getControllerId(),
|
||||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata"));
|
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata"));
|
||||||
|
if (response.getTargetType() != null) {
|
||||||
|
response.add(linkTo(methodOn(MgmtTargetTypeRestApi.class)
|
||||||
|
.getTargetType(response.getTargetType())).withRel(MgmtRestConstants.TARGET_V1_ASSIGNED_TARGET_TYPE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addPollStatus(final Target target, final MgmtTarget targetRest) {
|
static void addPollStatus(final Target target, final MgmtTarget targetRest) {
|
||||||
@@ -153,6 +159,9 @@ public final class MgmtTargetMapper {
|
|||||||
if (installationDate != null) {
|
if (installationDate != null) {
|
||||||
targetRest.setInstalledAt(installationDate);
|
targetRest.setInstalledAt(installationDate);
|
||||||
}
|
}
|
||||||
|
if (target.getTargetType() != null){
|
||||||
|
targetRest.setTargetType(target.getTargetType().getId());
|
||||||
|
}
|
||||||
|
|
||||||
targetRest.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(target.getControllerId())).withSelfRel());
|
targetRest.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(target.getControllerId())).withSelfRel());
|
||||||
|
|
||||||
@@ -172,7 +181,7 @@ public final class MgmtTargetMapper {
|
|||||||
private static TargetCreate fromRequest(final EntityFactory entityFactory, final MgmtTargetRequestBody targetRest) {
|
private static TargetCreate fromRequest(final EntityFactory entityFactory, final MgmtTargetRequestBody targetRest) {
|
||||||
return entityFactory.target().create().controllerId(targetRest.getControllerId()).name(targetRest.getName())
|
return entityFactory.target().create().controllerId(targetRest.getControllerId()).name(targetRest.getName())
|
||||||
.description(targetRest.getDescription()).securityToken(targetRest.getSecurityToken())
|
.description(targetRest.getDescription()).securityToken(targetRest.getSecurityToken())
|
||||||
.address(targetRest.getAddress());
|
.address(targetRest.getAddress()).targetType(targetRest.getTargetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<MetaData> fromRequestTargetMetadata(final List<MgmtMetadata> metadata,
|
static List<MetaData> fromRequestTargetMetadata(final List<MgmtMetadata> metadata,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import java.util.stream.Collectors;
|
|||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||||
@@ -140,7 +141,8 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
|
|||||||
|
|
||||||
final Target updateTarget = this.targetManagement.update(entityFactory.target().update(targetId)
|
final Target updateTarget = this.targetManagement.update(entityFactory.target().update(targetId)
|
||||||
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
|
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
|
||||||
.securityToken(targetRest.getSecurityToken()).requestAttributes(targetRest.isRequestAttributes()));
|
.targetType(targetRest.getTargetType()).securityToken(targetRest.getSecurityToken())
|
||||||
|
.requestAttributes(targetRest.isRequestAttributes()));
|
||||||
|
|
||||||
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget);
|
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget);
|
||||||
MgmtTargetMapper.addPollStatus(updateTarget, response);
|
MgmtTargetMapper.addPollStatus(updateTarget, response);
|
||||||
@@ -156,6 +158,18 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
|
|||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> unassignTargetType(@PathVariable("targetId") final String targetId) {
|
||||||
|
this.targetManagement.unAssignType(targetId);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> assignTargetType(@PathVariable("targetId") final String targetId, @RequestBody final MgmtId targetTypeId) {
|
||||||
|
this.targetManagement.assignType(targetId, targetTypeId.getId());
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("targetId") final String targetId) {
|
public ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("targetId") final String targetId) {
|
||||||
final Map<String, String> controllerAttributes = targetManagement.getControllerAttributes(targetId);
|
final Map<String, String> controllerAttributes = targetManagement.getControllerAttributes(targetId);
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.rest.resource;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetType;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPost;
|
||||||
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||||
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||||
|
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||||
|
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
import org.eclipse.hawkbit.rest.data.ResponseList;
|
||||||
|
|
||||||
|
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||||
|
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapper which maps repository model to RESTful model representation and
|
||||||
|
* back.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class MgmtTargetTypeMapper {
|
||||||
|
|
||||||
|
// private constructor, utility class
|
||||||
|
private MgmtTargetTypeMapper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<TargetTypeCreate> targetFromRequest(final EntityFactory entityFactory,
|
||||||
|
final Collection<MgmtTargetTypeRequestBodyPost> targetTypesRest) {
|
||||||
|
if (targetTypesRest == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return targetTypesRest.stream().map(targetRest -> fromRequest(entityFactory, targetRest)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TargetTypeCreate fromRequest(final EntityFactory entityFactory,
|
||||||
|
final MgmtTargetTypeRequestBodyPost targetTypesRest) {
|
||||||
|
return entityFactory.targetType().create().name(targetTypesRest.getName()).description(targetTypesRest.getDescription())
|
||||||
|
.colour(targetTypesRest.getColour()).compatible(getDistributionSets(targetTypesRest));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Collection<Long> getDistributionSets(final MgmtTargetTypeRequestBodyPost targetTypesRest) {
|
||||||
|
return Optional.ofNullable(targetTypesRest.getCompatibleDsTypes())
|
||||||
|
.map(ds -> ds.stream().map(MgmtDistributionSetTypeAssignment::getId).collect(Collectors.toList()))
|
||||||
|
.orElse(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<MgmtTargetType> toListResponse(final List<TargetType> types) {
|
||||||
|
if (types == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return new ResponseList<>(types.stream().map(MgmtTargetTypeMapper::toResponse).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static MgmtTargetType toResponse(final TargetType type) {
|
||||||
|
final MgmtTargetType result = new MgmtTargetType();
|
||||||
|
MgmtRestModelMapper.mapNamedToNamed(result, type);
|
||||||
|
result.setTypeId(type.getId());
|
||||||
|
result.setColour(type.getColour());
|
||||||
|
result.add(linkTo(methodOn(MgmtTargetTypeRestApi.class).getTargetType(result.getTypeId())).withSelfRel());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addLinks(final MgmtTargetType result) {
|
||||||
|
result.add(linkTo(methodOn(MgmtTargetTypeRestApi.class).getCompatibleDistributionSets(result.getTypeId()))
|
||||||
|
.withRel(MgmtRestConstants.TARGETTYPE_V1_DS_TYPES));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.rest.resource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetType;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPost;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPut;
|
||||||
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||||
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||||
|
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||||
|
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||||
|
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Slice;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST Resource handling for {@link TargetType} CRUD operations.
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class MgmtTargetTypeResource implements MgmtTargetTypeRestApi {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(MgmtTargetTypeResource.class);
|
||||||
|
|
||||||
|
private final TargetTypeManagement targetTypeManagement;
|
||||||
|
private final EntityFactory entityFactory;
|
||||||
|
|
||||||
|
public MgmtTargetTypeResource(TargetTypeManagement targetTypeManagement, final EntityFactory entityFactory) {
|
||||||
|
this.targetTypeManagement = targetTypeManagement;
|
||||||
|
this.entityFactory = entityFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<PagedList<MgmtTargetType>> getTargetTypes(
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||||
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||||
|
|
||||||
|
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||||
|
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||||
|
final Sort sorting = PagingUtility.sanitizeTargetTypeSortParam(sortParam);
|
||||||
|
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||||
|
|
||||||
|
final Page<TargetType> findTargetTypesAll;
|
||||||
|
long countTargetTypesAll;
|
||||||
|
if (rsqlParam != null) {
|
||||||
|
findTargetTypesAll= targetTypeManagement.findByRsql(pageable, rsqlParam);
|
||||||
|
} else {
|
||||||
|
findTargetTypesAll = targetTypeManagement.findAll(pageable);
|
||||||
|
}
|
||||||
|
countTargetTypesAll = findTargetTypesAll.getTotalElements();
|
||||||
|
|
||||||
|
final List<MgmtTargetType> rest = MgmtTargetTypeMapper.toListResponse(findTargetTypesAll.getContent());
|
||||||
|
return ResponseEntity.ok(new PagedList<>(rest, countTargetTypesAll));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<MgmtTargetType> getTargetType(@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||||
|
final TargetType foundType = findTargetTypeWithExceptionIfNotFound(targetTypeId);
|
||||||
|
final MgmtTargetType response = MgmtTargetTypeMapper.toResponse(foundType);
|
||||||
|
MgmtTargetTypeMapper.addLinks(response);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> deleteTargetType(@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||||
|
LOG.debug("Delete {} target type", targetTypeId);
|
||||||
|
targetTypeManagement.delete(targetTypeId);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<MgmtTargetType> updateTargetType(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||||
|
@RequestBody final MgmtTargetTypeRequestBodyPut restTargetType) {
|
||||||
|
|
||||||
|
final TargetType updated = targetTypeManagement
|
||||||
|
.update(entityFactory.targetType().update(targetTypeId).name(restTargetType.getName())
|
||||||
|
.description(restTargetType.getDescription()).colour(restTargetType.getColour()));
|
||||||
|
final MgmtTargetType response = MgmtTargetTypeMapper.toResponse(updated);
|
||||||
|
MgmtTargetTypeMapper.addLinks(response);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<List<MgmtTargetType>> createTargetTypes(
|
||||||
|
@RequestBody final List<MgmtTargetTypeRequestBodyPost> targetTypes) {
|
||||||
|
|
||||||
|
final List<TargetType> createdTargetTypes = targetTypeManagement
|
||||||
|
.create(MgmtTargetTypeMapper.targetFromRequest(entityFactory, targetTypes));
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtTargetTypeMapper.toListResponse(createdTargetTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<List<MgmtDistributionSetType>> getCompatibleDistributionSets(
|
||||||
|
@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||||
|
|
||||||
|
final TargetType foundType = findTargetTypeWithExceptionIfNotFound(targetTypeId);
|
||||||
|
return ResponseEntity
|
||||||
|
.ok(MgmtDistributionSetTypeMapper.toListResponse(foundType.getCompatibleDistributionSetTypes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> removeCompatibleDistributionSet(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||||
|
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||||
|
|
||||||
|
targetTypeManagement.unassignDistributionSetType(targetTypeId, distributionSetTypeId);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> addCompatibleDistributionSets(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||||
|
@RequestBody final List<MgmtDistributionSetTypeAssignment> distributionSetTypeIds) {
|
||||||
|
|
||||||
|
targetTypeManagement.assignCompatibleDistributionSetTypes(targetTypeId,
|
||||||
|
distributionSetTypeIds.stream().map(MgmtDistributionSetTypeAssignment::getId).collect(Collectors.toList()));
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TargetType findTargetTypeWithExceptionIfNotFound(final Long targetTypeId) {
|
||||||
|
return targetTypeManagement.get(targetTypeId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
|
|||||||
import org.eclipse.hawkbit.repository.TagFields;
|
import org.eclipse.hawkbit.repository.TagFields;
|
||||||
import org.eclipse.hawkbit.repository.TargetFields;
|
import org.eclipse.hawkbit.repository.TargetFields;
|
||||||
import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
|
import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
|
||||||
|
import org.eclipse.hawkbit.repository.TargetTypeFields;
|
||||||
import org.eclipse.hawkbit.rest.util.SortUtility;
|
import org.eclipse.hawkbit.rest.util.SortUtility;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.domain.Sort.Direction;
|
import org.springframework.data.domain.Sort.Direction;
|
||||||
@@ -61,6 +62,14 @@ public final class PagingUtility {
|
|||||||
return Sort.by(SortUtility.parse(TargetFields.class, sortParam));
|
return Sort.by(SortUtility.parse(TargetFields.class, sortParam));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Sort sanitizeTargetTypeSortParam(final String sortParam) {
|
||||||
|
if (sortParam == null) {
|
||||||
|
// default
|
||||||
|
return Sort.by(Direction.ASC, TargetTypeFields.ID.getFieldName());
|
||||||
|
}
|
||||||
|
return Sort.by(SortUtility.parse(TargetFields.class, sortParam));
|
||||||
|
}
|
||||||
|
|
||||||
static Sort sanitizeTagSortParam(final String sortParam) {
|
static Sort sanitizeTagSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import java.util.Iterator;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.validation.ConstraintViolationException;
|
import javax.validation.ConstraintViolationException;
|
||||||
@@ -56,6 +57,7 @@ import org.eclipse.hawkbit.repository.model.Rollout;
|
|||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||||
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
|
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
|
||||||
@@ -63,6 +65,7 @@ import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
|||||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||||
import org.eclipse.hawkbit.util.IpUtil;
|
import org.eclipse.hawkbit.util.IpUtil;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -105,6 +108,7 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
|||||||
private static final String JSON_PATH_FIELD_SIZE = ".size";
|
private static final String JSON_PATH_FIELD_SIZE = ".size";
|
||||||
private static final String JSON_PATH_FIELD_TOTAL = ".total";
|
private static final String JSON_PATH_FIELD_TOTAL = ".total";
|
||||||
private static final String JSON_PATH_FIELD_LAST_REQUEST_AT = ".lastControllerRequestAt";
|
private static final String JSON_PATH_FIELD_LAST_REQUEST_AT = ".lastControllerRequestAt";
|
||||||
|
private static final String JSON_PATH_FIELD_TARGET_TYPE = ".targetType";
|
||||||
|
|
||||||
// target
|
// target
|
||||||
// $.field
|
// $.field
|
||||||
@@ -117,6 +121,7 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
|||||||
private static final String JSON_PATH_CONTROLLERID = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTROLLERID;
|
private static final String JSON_PATH_CONTROLLERID = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTROLLERID;
|
||||||
private static final String JSON_PATH_DESCRIPTION = JSON_PATH_ROOT + JSON_PATH_FIELD_DESCRIPTION;
|
private static final String JSON_PATH_DESCRIPTION = JSON_PATH_ROOT + JSON_PATH_FIELD_DESCRIPTION;
|
||||||
private static final String JSON_PATH_LAST_REQUEST_AT = JSON_PATH_ROOT + JSON_PATH_FIELD_LAST_REQUEST_AT;
|
private static final String JSON_PATH_LAST_REQUEST_AT = JSON_PATH_ROOT + JSON_PATH_FIELD_LAST_REQUEST_AT;
|
||||||
|
private static final String JSON_PATH_TYPE = JSON_PATH_ROOT + JSON_PATH_FIELD_TARGET_TYPE;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JpaProperties jpaProperties;
|
private JpaProperties jpaProperties;
|
||||||
@@ -2075,4 +2080,192 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
|||||||
"$._links.rollout.href", containsString("/rest/v1/rollouts/" + rollout.getId().intValue())));
|
"$._links.rollout.href", containsString("/rest/v1/rollouts/" + rollout.getId().intValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that a post request for creating targets with target type works.")
|
||||||
|
public void createTargetsWithTargetType() throws Exception {
|
||||||
|
final TargetType type1 = testdataFactory.createTargetType("typeWithDs", Collections.singletonList(standardDsType));
|
||||||
|
final TargetType type2 = testdataFactory.createTargetType("typeWithOutDs", Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
final Target test1 = entityFactory.target().create().controllerId("id1").name("targetWithoutType")
|
||||||
|
.securityToken("token").address("amqp://test123/foobar").description("testid1").build();
|
||||||
|
final Target test2 = entityFactory.target().create().controllerId("id2").name("targetOfType1")
|
||||||
|
.targetType(type1.getId()).description("testid2").build();
|
||||||
|
final Target test3 = entityFactory.target().create().controllerId("id3").name("targetOfType2")
|
||||||
|
.targetType(type2.getId()).description("testid3").build();
|
||||||
|
final String hrefType1 = "http://localhost/rest/v1/targettypes/" + type1.getId();
|
||||||
|
|
||||||
|
final List<Target> targets = Arrays.asList(test1, test2, test3);
|
||||||
|
|
||||||
|
final MvcResult mvcPostResult = mvc
|
||||||
|
.perform(post("/rest/v1/targets/").content(JsonBuilder.targets(targets, true))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("[0].name", equalTo("targetWithoutType")))
|
||||||
|
.andExpect(jsonPath("[0].controllerId", equalTo("id1")))
|
||||||
|
.andExpect(jsonPath("[0].description", equalTo("testid1")))
|
||||||
|
.andExpect(jsonPath("[0].createdAt", not(equalTo(0))))
|
||||||
|
.andExpect(jsonPath("[0].createdBy", equalTo("bumlux")))
|
||||||
|
.andExpect(jsonPath("[0].securityToken", equalTo("token")))
|
||||||
|
.andExpect(jsonPath("[0].address", equalTo("amqp://test123/foobar")))
|
||||||
|
.andExpect(jsonPath("[0].targetType").doesNotExist())
|
||||||
|
.andExpect(jsonPath("[1].name", equalTo("targetOfType1")))
|
||||||
|
.andExpect(jsonPath("[1].createdBy", equalTo("bumlux")))
|
||||||
|
.andExpect(jsonPath("[1].controllerId", equalTo("id2")))
|
||||||
|
.andExpect(jsonPath("[1].description", equalTo("testid2")))
|
||||||
|
.andExpect(jsonPath("[1].createdAt", not(equalTo(0))))
|
||||||
|
.andExpect(jsonPath("[1].createdBy", equalTo("bumlux")))
|
||||||
|
.andExpect(jsonPath("[1].targetType", equalTo(type1.getId().intValue())))
|
||||||
|
.andExpect(jsonPath("[2].name", equalTo("targetOfType2")))
|
||||||
|
.andExpect(jsonPath("[2].controllerId", equalTo("id3")))
|
||||||
|
.andExpect(jsonPath("[2].description", equalTo("testid3")))
|
||||||
|
.andExpect(jsonPath("[2].createdAt", not(equalTo(0))))
|
||||||
|
.andExpect(jsonPath("[2].createdBy", equalTo("bumlux")))
|
||||||
|
.andExpect(jsonPath("[2].targetType", equalTo(type2.getId().intValue())))
|
||||||
|
.andReturn();
|
||||||
|
|
||||||
|
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + test2.getControllerId()))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath(JSON_PATH_NAME, equalTo("targetOfType1")))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_CONTROLLERID, equalTo("id2")))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_TYPE, equalTo(type1.getId().intValue())))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_DESCRIPTION, equalTo("testid2")))
|
||||||
|
.andExpect(jsonPath("$._links.targetType.href", equalTo(hrefType1))).andReturn();
|
||||||
|
|
||||||
|
assertThat(targetManagement.getByControllerID("id1")).isNotNull();
|
||||||
|
assertThat(targetManagement.getByControllerID("id1").get().getName()).isEqualTo("targetWithoutType");
|
||||||
|
assertThat(targetManagement.getByControllerID("id1").get().getDescription()).isEqualTo("testid1");
|
||||||
|
assertThat(targetManagement.getByControllerID("id1").get().getTargetType()).isNull();
|
||||||
|
assertThat(targetManagement.getByControllerID("id1").get().getSecurityToken()).isEqualTo("token");
|
||||||
|
assertThat(targetManagement.getByControllerID("id1").get().getAddress().toString())
|
||||||
|
.isEqualTo("amqp://test123/foobar");
|
||||||
|
assertThat(targetManagement.getByControllerID("id2")).isNotNull();
|
||||||
|
assertThat(targetManagement.getByControllerID("id2").get().getName()).isEqualTo("targetOfType1");
|
||||||
|
assertThat(targetManagement.getByControllerID("id2").get().getDescription()).isEqualTo("testid2");
|
||||||
|
assertThat(targetManagement.getByControllerID("id2").get().getTargetType().getName()).isEqualTo("typeWithDs");
|
||||||
|
assertThat(targetManagement.getByControllerID("id3")).isNotNull();
|
||||||
|
assertThat(targetManagement.getByControllerID("id3").get().getName()).isEqualTo("targetOfType2");
|
||||||
|
assertThat(targetManagement.getByControllerID("id3").get().getDescription()).isEqualTo("testid3");
|
||||||
|
assertThat(targetManagement.getByControllerID("id3").get().getTargetType().getName()).isEqualTo("typeWithOutDs");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that a post request for creating target with target type works.")
|
||||||
|
public void createTargetWithExistingTargetType() throws Exception {
|
||||||
|
// create target type
|
||||||
|
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype",1);
|
||||||
|
assertThat(targetTypes).hasSize(1);
|
||||||
|
|
||||||
|
final Target target = entityFactory.target().create().controllerId("targetcontroller").name("testtarget").targetType(targetTypes.get(0).getId()).build();
|
||||||
|
|
||||||
|
final String targetList = JsonBuilder.targets(Collections.singletonList(target), false);
|
||||||
|
|
||||||
|
// test query target over rest resource
|
||||||
|
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).content(targetList)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("[0].controllerId", equalTo("targetcontroller")))
|
||||||
|
.andExpect(jsonPath("[0].targetType", equalTo(targetTypes.get(0).getId().intValue())));
|
||||||
|
|
||||||
|
assertThat(targetManagement.getByControllerID("targetcontroller").get().getTargetType().getId()).isEqualTo(targetTypes.get(0).getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that a put request for updating targets with target type works.")
|
||||||
|
public void updateTargetTypeInTarget() throws Exception {
|
||||||
|
// create target type
|
||||||
|
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype",2);
|
||||||
|
assertThat(targetTypes).hasSize(2);
|
||||||
|
|
||||||
|
String controllerId = "targetcontroller";
|
||||||
|
Target target = testdataFactory.createTarget(controllerId, "testtarget", targetTypes.get(0).getId());
|
||||||
|
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
assertThat(target.getTargetType().getId()).isEqualTo(targetTypes.get(0).getId());
|
||||||
|
|
||||||
|
// update target over rest resource
|
||||||
|
final String body = new JSONObject().put("targetType", targetTypes.get(1).getId().intValue()).toString();
|
||||||
|
|
||||||
|
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId).content(body)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("controllerId", equalTo(controllerId)))
|
||||||
|
.andExpect(jsonPath("targetType", equalTo(targetTypes.get(1).getId().intValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that a post request for creating targets with unknown target type fails.")
|
||||||
|
public void addingNonExistingTargetTypeInTargetShouldFail() throws Exception {
|
||||||
|
long unknownTargetTypeId = 999;
|
||||||
|
String errorMsg = String.format("TargetType with given identifier {%s} does not exist.", unknownTargetTypeId);
|
||||||
|
|
||||||
|
Optional<TargetType> targetType = targetTypeManagement.get(unknownTargetTypeId);
|
||||||
|
assertThat(targetType).isNotPresent();
|
||||||
|
|
||||||
|
String controllerId = "targetcontroller";
|
||||||
|
final Target target = entityFactory.target().create().controllerId(controllerId).name("testtarget").build();
|
||||||
|
|
||||||
|
final String targetList = JsonBuilder.targets(Collections.singletonList(target), false, unknownTargetTypeId);
|
||||||
|
|
||||||
|
// post target over rest resource
|
||||||
|
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING).content(targetList)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isNotFound())
|
||||||
|
.andExpect(jsonPath("message", Matchers.containsString(errorMsg)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that a post request for assign target type to target works.")
|
||||||
|
public void assignTargetTypeToTarget() throws Exception {
|
||||||
|
// create target type
|
||||||
|
TargetType targetType = testdataFactory.findOrCreateTargetType("targettype");
|
||||||
|
assertThat(targetType).isNotNull();
|
||||||
|
|
||||||
|
// create target
|
||||||
|
String targetControllerId = "targetcontroller";
|
||||||
|
Target target = testdataFactory.createTarget(targetControllerId, "testtarget");
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
|
||||||
|
// assign target type over rest resource
|
||||||
|
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetControllerId + "/targettype")
|
||||||
|
.content("{\"id\":" + targetType.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||||
|
|
||||||
|
assertThat(targetManagement.getByControllerID(targetControllerId).get().getTargetType().getId()).isEqualTo(targetType.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that a post request for assign a invalid target type to target fails.")
|
||||||
|
public void assignInvalidTargetTypeToTargetFails() throws Exception {
|
||||||
|
// Invalid target type ID
|
||||||
|
long invalidTargetTypeId = 999;
|
||||||
|
|
||||||
|
// create target
|
||||||
|
String targetControllerId = "targetcontroller";
|
||||||
|
Target target = testdataFactory.createTarget(targetControllerId, "testtarget");
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
|
||||||
|
// assign invalid target type over rest resource
|
||||||
|
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetControllerId + "/targettype")
|
||||||
|
.content("{\"id\":" + invalidTargetTypeId + "}").contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that a delete request for unassign target type from target works.")
|
||||||
|
public void unassignTargetTypeFromTarget() throws Exception {
|
||||||
|
// create target type
|
||||||
|
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype",1);
|
||||||
|
assertThat(targetTypes).hasSize(1);
|
||||||
|
|
||||||
|
String targetControllerId = "targetcontroller";
|
||||||
|
Target target = testdataFactory.createTarget(targetControllerId, "testtarget", targetTypes.get(0).getId());
|
||||||
|
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
assertThat(target.getTargetType().getId()).isEqualTo(targetTypes.get(0).getId());
|
||||||
|
|
||||||
|
// unassign target type over rest resource
|
||||||
|
mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetControllerId + "/targettype")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
|
||||||
|
|
||||||
|
assertThat(targetManagement.getByControllerID(targetControllerId).get().getTargetType()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,616 @@
|
|||||||
|
/**
|
||||||
|
* 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.mgmt.rest.resource;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.jayway.jsonpath.JsonPath;
|
||||||
|
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.im.authentication.SpPermission;
|
||||||
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||||
|
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||||
|
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.util.WithUser;
|
||||||
|
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||||
|
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.hamcrest.Matchers.hasToString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring MVC Tests against the MgmtTargetTypeResource.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Feature("Component Tests - Management API")
|
||||||
|
@Story("Target Type Resource")
|
||||||
|
class MgmtTargetTypeResourceTest extends AbstractManagementApiIntegrationTest {
|
||||||
|
|
||||||
|
private final static String TARGETTYPES_ENDPOINT = MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING;
|
||||||
|
private final static String TARGETTYPE_SINGLE_ENDPOINT = MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING
|
||||||
|
+ "/{typeid}";
|
||||||
|
private final static String TARGETTYPE_DSTYPES_ENDPOINT = TARGETTYPE_SINGLE_ENDPOINT + "/"
|
||||||
|
+ MgmtRestConstants.TARGETTYPE_V1_DS_TYPES;
|
||||||
|
private final static String TARGETTYPE_DSTYPE_SINGLE_ENDPOINT = TARGETTYPE_DSTYPES_ENDPOINT + "/{dstypeid}";
|
||||||
|
|
||||||
|
private final static String TEST_USER = "targetTypeTester";
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = "targetTypeTester", allSpPermissions = true, removeFromAllPermission = { SpPermission.READ_TARGET })
|
||||||
|
@Description("GET targettypes returns Forbidden when permission is missing")
|
||||||
|
void getTargetTypesWithoutPermission() throws Exception {
|
||||||
|
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{id} GET request.")
|
||||||
|
void getTargetType() throws Exception {
|
||||||
|
String typeName = "TestTypeGET";
|
||||||
|
TargetType testType = createTestTargetTypeInDB(typeName);
|
||||||
|
Long typeId = testType.getId();
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, typeId).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("$.id", is(typeId), Long.class)).andExpect(jsonPath("$.name", equalTo(typeName)))
|
||||||
|
.andExpect(jsonPath("$.colour", is("#000000")))
|
||||||
|
.andExpect(jsonPath("$.description", equalTo(typeName + " description")))
|
||||||
|
.andExpect(jsonPath("$.createdBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("$.lastModifiedBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||||
|
.andExpect(jsonPath("$._links.self.href", equalTo("http://localhost/rest/v1/targettypes/" + typeId)))
|
||||||
|
.andExpect(jsonPath("$.deleted").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.key").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$._links.compatibledistributionsettypes.href",
|
||||||
|
equalTo("http://localhost/rest/v1/targettypes/" + typeId + "/compatibledistributionsettypes")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests.")
|
||||||
|
void getTargetTypes() throws Exception {
|
||||||
|
String typeName = "TestTypeGET";
|
||||||
|
int count = 5;
|
||||||
|
List<TargetType> testTypes = createTestTargetTypesInDB(typeName, count);
|
||||||
|
|
||||||
|
ResultActions resultActions = mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print());
|
||||||
|
|
||||||
|
for (int index = 0; index < count; index++) {
|
||||||
|
Long typeId = testTypes.get(index).getId();
|
||||||
|
resultActions.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].id", contains(typeId.intValue())))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].name", contains(typeName + index)))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].colour", contains("#000000")))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].description",
|
||||||
|
contains(typeName + " description")))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].createdBy", contains(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].createdAt",
|
||||||
|
contains(testTypes.get(index).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].lastModifiedBy", contains(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].lastModifiedAt",
|
||||||
|
contains(testTypes.get(index).getLastModifiedAt())))
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].deleted").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].key").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')]._links.self.href",
|
||||||
|
contains("http://localhost/rest/v1/targettypes/" + typeId)))
|
||||||
|
.andExpect(
|
||||||
|
jsonPath("$.content.[?(@.id=='" + typeId + "')]._links.compatibledistributionsettypes.href")
|
||||||
|
.doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.total", equalTo(count))).andExpect(jsonPath("$.size", equalTo(count)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests without prior created target types.")
|
||||||
|
void getDefaultTargetTypes() throws Exception {
|
||||||
|
|
||||||
|
// 0 types overall (no default types are created)
|
||||||
|
final int types = 0;
|
||||||
|
mvc.perform(get(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types)))
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with sorting by name.")
|
||||||
|
void getTargetTypesSortedByName() throws Exception {
|
||||||
|
String typeNameA = "ATestTypeGETsorted";
|
||||||
|
String typeNameB = "BTestTypeGETsorted";
|
||||||
|
String typeNameC = "CTestTypeGETsorted";
|
||||||
|
TargetType testTypeB = createTestTargetTypeInDB(typeNameB);
|
||||||
|
TargetType testTypeC = createTestTargetTypeInDB(typeNameC);
|
||||||
|
TargetType testTypeA = createTestTargetTypeInDB(typeNameA);
|
||||||
|
|
||||||
|
testTypeA = targetTypeManagement
|
||||||
|
.update(entityFactory.targetType().update(testTypeA.getId()).description("Updated description"));
|
||||||
|
|
||||||
|
// descending
|
||||||
|
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON)
|
||||||
|
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "name:DESC")).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("$.content.[0].id", equalTo(testTypeC.getId().intValue())))
|
||||||
|
.andExpect(jsonPath("$.content.[0].name", equalTo(typeNameC)))
|
||||||
|
.andExpect(jsonPath("$.content.[0].colour", equalTo("#000000")))
|
||||||
|
.andExpect(jsonPath("$.content.[0].description", equalTo(typeNameC + " description")))
|
||||||
|
.andExpect(jsonPath("$.content.[0].createdBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testTypeC.getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testTypeC.getLastModifiedAt())))
|
||||||
|
.andExpect(jsonPath("$.content.[0].deleted").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.content.[0].key").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.content.[0]._links.self.href",
|
||||||
|
equalTo("http://localhost/rest/v1/targettypes/" + testTypeC.getId())))
|
||||||
|
.andExpect(jsonPath("$.content.[0]._links.compatibledistributionsettypes.href").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.total", equalTo(3))).andExpect(jsonPath("$.size", equalTo(3)))
|
||||||
|
.andExpect(jsonPath("$.content.[1].name", equalTo(typeNameB)))
|
||||||
|
.andExpect(jsonPath("$.content.[2].name", equalTo(typeNameA)));
|
||||||
|
|
||||||
|
// ascending
|
||||||
|
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON)
|
||||||
|
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "name:ASC")).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("$.content.[0].id", equalTo(testTypeA.getId().intValue())))
|
||||||
|
.andExpect(jsonPath("$.content.[0].name", equalTo(typeNameA)))
|
||||||
|
.andExpect(jsonPath("$.content.[0].description", equalTo("Updated description")))
|
||||||
|
.andExpect(jsonPath("$.content.[0].colour", equalTo("#000000")))
|
||||||
|
.andExpect(jsonPath("$.content.[0].createdBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testTypeA.getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testTypeA.getLastModifiedAt())))
|
||||||
|
.andExpect(jsonPath("$.content.[0].deleted").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.content.[0].key").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.content.[0]._links.self.href",
|
||||||
|
equalTo("http://localhost/rest/v1/targettypes/" + testTypeA.getId())))
|
||||||
|
.andExpect(jsonPath("$.content.[0]._links.compatibledistributionsettypes.href").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.total", equalTo(3))).andExpect(jsonPath("$.size", equalTo(3)))
|
||||||
|
.andExpect(jsonPath("$.content.[1].name", equalTo(typeNameB)))
|
||||||
|
.andExpect(jsonPath("$.content.[2].name", equalTo(typeNameC)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with paging.")
|
||||||
|
void getTargetTypesWithPagingLimitRequestParameter() throws Exception {
|
||||||
|
final String typePrefix = "TestTypeGETPaging";
|
||||||
|
final int count = 10;
|
||||||
|
final int limit = 3;
|
||||||
|
createTestTargetTypesInDB(typePrefix, count);
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPES_ENDPOINT).param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT,
|
||||||
|
String.valueOf(limit))).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(count)))
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limit)))
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limit)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with paging and offset.")
|
||||||
|
void getTargetTypesWithPagingLimitAndOffsetRequestParameter() throws Exception {
|
||||||
|
final int count = 10;
|
||||||
|
final int offset = 2;
|
||||||
|
final int expectedSize = count - offset;
|
||||||
|
final String typePrefix = "TestTypeGETPaging";
|
||||||
|
createTestTargetTypesInDB(typePrefix, count);
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPES_ENDPOINT)
|
||||||
|
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offset))
|
||||||
|
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(count)))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(count)))
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
|
||||||
|
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} PUT requests.")
|
||||||
|
void updateTargetType() throws Exception {
|
||||||
|
String typeName = "TestTypePUT";
|
||||||
|
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||||
|
final String body = new JSONObject().put("id", testType.getId()).put("description", "updated description")
|
||||||
|
.put("name", "TestTypePUTupdated").put("colour", "#ffffff").toString();
|
||||||
|
|
||||||
|
mvc.perform(
|
||||||
|
put(TARGETTYPE_SINGLE_ENDPOINT, testType.getId()).content(body).contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||||
|
.andExpect(jsonPath("$.description", equalTo("updated description")))
|
||||||
|
.andExpect(jsonPath("$.name", equalTo("TestTypePUTupdated")))
|
||||||
|
.andExpect(jsonPath("$.colour", equalTo("#ffffff"))).andReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{id} GET requests.")
|
||||||
|
void getUpdatedTargetType() throws Exception {
|
||||||
|
TargetType testType = createTestTargetTypeInDB("TestTypeGET");
|
||||||
|
String typeNameUpdated = "TestTypeGETupdated";
|
||||||
|
testType = targetTypeManagement.update(entityFactory.targetType().update(testType.getId()).name(typeNameUpdated)
|
||||||
|
.description("Updated Description").colour("#ffffff"));
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, testType.getId()).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("$.name", equalTo(typeNameUpdated)))
|
||||||
|
.andExpect(jsonPath("$.description", equalTo("Updated Description")))
|
||||||
|
.andExpect(jsonPath("$.colour", equalTo("#ffffff")))
|
||||||
|
.andExpect(jsonPath("$.createdBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("$.lastModifiedBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||||
|
.andExpect(jsonPath("$.deleted").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.key").doesNotExist());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes POST requests.")
|
||||||
|
void createTargetTypes() throws Exception {
|
||||||
|
String typeName = "TestTypePOST";
|
||||||
|
final List<TargetType> types = buildTestTargetTypesWithoutDsTypes(typeName, 5);
|
||||||
|
|
||||||
|
runPostTargetTypeAndVerify(types);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes POST requests.")
|
||||||
|
void addDistributionSetTypeToTargetType() throws Exception {
|
||||||
|
String typeName = "TestTypeAddDs";
|
||||||
|
TargetType testType = createTestTargetTypeInDB(typeName);
|
||||||
|
assertThat(testType.getOptLockRevision()).isEqualTo(1);
|
||||||
|
|
||||||
|
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())
|
||||||
|
.content("[{\"id\":" + standardDsType.getId() + "}]").contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||||
|
|
||||||
|
testType = targetTypeManagement.get(testType.getId()).get();
|
||||||
|
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
|
||||||
|
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||||
|
assertThat(testType.getCompatibleDistributionSetTypes()).containsExactly(standardDsType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes GET requests.")
|
||||||
|
void getDistributionSetsOfTargetType() throws Exception {
|
||||||
|
String typeName = "TestTypeGetDs";
|
||||||
|
final TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("$[0].name", equalTo(standardDsType.getName())))
|
||||||
|
.andExpect(jsonPath("$[0].description", equalTo(standardDsType.getDescription())))
|
||||||
|
.andExpect(jsonPath("$[0].key", equalTo("test_default_ds_type")))
|
||||||
|
.andExpect(jsonPath("$[0]._links.self.href",
|
||||||
|
equalTo("http://localhost/rest/v1/distributionsettypes/" + standardDsType.getId())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes/{ID} GET requests.")
|
||||||
|
void getDistributionSetOfTargetTypeReturnsNotAllowed() throws Exception {
|
||||||
|
String typeName = "TestTypeAddDs";
|
||||||
|
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), standardDsType.getId())
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isMethodNotAllowed());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes/{ID} DELETE requests.")
|
||||||
|
void removeDsTypeFromTargetType() throws Exception {
|
||||||
|
String typeName = "TestTypeRemoveDs";
|
||||||
|
TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mvc.perform(delete(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), standardDsType.getId())
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
testType = targetTypeManagement.get(testType.getId()).get();
|
||||||
|
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
|
||||||
|
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||||
|
assertThat(testType.getCompatibleDistributionSetTypes()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} DELETE requests.")
|
||||||
|
void deletingDsTypeRemovesAssignmentFromTargetType() throws Exception {
|
||||||
|
String typeName = "TestTypeRemoveDs";
|
||||||
|
TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||||
|
assertThat(testType.getCompatibleDistributionSetTypes()).hasSize(1);
|
||||||
|
assertThat(distributionSetTypeManagement.getByKey(standardDsType.getKey())).isNotEmpty();
|
||||||
|
|
||||||
|
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/" + standardDsType.getId()))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||||
|
|
||||||
|
testType = targetTypeManagement.get(testType.getId()).get();
|
||||||
|
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
|
||||||
|
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||||
|
assertThat(testType.getCompatibleDistributionSetTypes()).isEmpty();
|
||||||
|
assertThat(distributionSetTypeManagement.getByKey(standardDsType.getKey())).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} DELETE requests - Deletion when not in use.")
|
||||||
|
void deleteTargetTypeUnused() throws Exception {
|
||||||
|
String typeName = "TestTypeUnusedDelete";
|
||||||
|
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||||
|
|
||||||
|
assertThat(targetTypeManagement.count()).isEqualTo(1);
|
||||||
|
|
||||||
|
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
assertThat(targetTypeManagement.count()).isZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} DELETE requests - Deletion not possible when in use.")
|
||||||
|
void deleteTargetTypeUsed() throws Exception {
|
||||||
|
String typeName = "TestTypeUsedDelete";
|
||||||
|
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||||
|
|
||||||
|
targetManagement.create(entityFactory.target().create().controllerId("target").name("TargetOfTestType")
|
||||||
|
.description("target description").targetType(testType.getId()));
|
||||||
|
|
||||||
|
assertThat(targetTypeManagement.count()).isEqualTo(1);
|
||||||
|
assertThat(targetManagement.count()).isEqualTo(1);
|
||||||
|
|
||||||
|
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isConflict());
|
||||||
|
|
||||||
|
assertThat(targetManagement.count()).isEqualTo(1);
|
||||||
|
assertThat(targetTypeManagement.count()).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Ensures that target type deletion request to API on an entity that does not exist results in NOT_FOUND.")
|
||||||
|
void deleteTargetTypeThatDoesNotExistLeadsToNotFound() throws Exception {
|
||||||
|
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, 1234)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||||
|
@Description("Tests the update of the deletion flag. It is verified that the target type can't be marked as deleted through update operation.")
|
||||||
|
void updateTargetTypeDeletedFlag() throws Exception {
|
||||||
|
String typeName = "TestTypePUT";
|
||||||
|
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||||
|
|
||||||
|
final String body = new JSONObject().put("id", testType.getId()).put("deleted", true).toString();
|
||||||
|
|
||||||
|
mvc.perform(
|
||||||
|
put(TARGETTYPE_SINGLE_ENDPOINT, testType.getId()).content(body).contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||||
|
.andExpect(jsonPath("$.deleted").doesNotExist());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).")
|
||||||
|
void invalidRequestsOnTargetTypesResource() throws Exception {
|
||||||
|
String typeName = "TestTypeInvalidReq";
|
||||||
|
final TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
// target type does not exist
|
||||||
|
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, 12345678)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, 123456789)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, 123456789)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
|
// target types at creation time invalid
|
||||||
|
final TargetType testNewType = createTestTargetTypeInDB(typeName + "Another",
|
||||||
|
Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mvc.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(Collections.singletonList(testNewType)))
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isUnsupportedMediaType());
|
||||||
|
|
||||||
|
// bad request - no content
|
||||||
|
mvc.perform(post(TARGETTYPES_ENDPOINT).contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||||
|
|
||||||
|
// bad request - bad content
|
||||||
|
mvc.perform(post(TARGETTYPES_ENDPOINT).content("sdfjsdlkjfskdjf".getBytes())
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
|
||||||
|
// Missing mandatory field name
|
||||||
|
mvc.perform(post(TARGETTYPES_ENDPOINT).content("[{\"description\":\"Desc123\"}]")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
|
||||||
|
final TargetType tooLongName = entityFactory.targetType().create()
|
||||||
|
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||||
|
mvc.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(Collections.singletonList(tooLongName)))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
|
||||||
|
// ds types
|
||||||
|
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
mvc.perform(delete(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||||
|
|
||||||
|
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("{\"id\":1}")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
|
||||||
|
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("[{\"id\":44456}]")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
|
// not allowed methods
|
||||||
|
mvc.perform(put(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isMethodNotAllowed());
|
||||||
|
|
||||||
|
mvc.perform(delete(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isMethodNotAllowed());
|
||||||
|
|
||||||
|
mvc.perform(put(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isMethodNotAllowed());
|
||||||
|
|
||||||
|
mvc.perform(delete(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId(), 565765)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isMethodNotAllowed());
|
||||||
|
|
||||||
|
mvc.perform(put(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
|
||||||
|
|
||||||
|
mvc.perform(post(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isMethodNotAllowed());
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Search request of target types.")
|
||||||
|
void searchTargetTypeRsql() throws Exception {
|
||||||
|
targetTypeManagement.create(entityFactory.targetType().create().name("TestName123"));
|
||||||
|
targetTypeManagement.create(entityFactory.targetType().create().name("TestName1234"));
|
||||||
|
|
||||||
|
final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234";
|
||||||
|
|
||||||
|
mvc.perform(get(TARGETTYPES_ENDPOINT + "?q=" + rsqlFindLikeDs1OrDs2)).andDo(MockMvcResultPrinter.print())
|
||||||
|
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(2)))
|
||||||
|
.andExpect(jsonPath("total", equalTo(2))).andExpect(jsonPath("content[0].name", equalTo("TestName123")))
|
||||||
|
.andExpect(jsonPath("content[1].name", equalTo("TestName1234")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private TargetType buildTestTargetTypeBody(String name) {
|
||||||
|
return prepareTestTargetType(name, null).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TargetTypeCreate prepareTestTargetType(String name, Collection<DistributionSetType> dsTypes) {
|
||||||
|
TargetTypeCreate create = entityFactory.targetType().create().name(name)
|
||||||
|
.description("Description of the test type").colour("#aaaaaa");
|
||||||
|
if (dsTypes != null && !dsTypes.isEmpty()) {
|
||||||
|
create.compatible(Collections.singletonList(standardDsType.getId()));
|
||||||
|
}
|
||||||
|
return create;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private List<TargetType> createTestTargetTypesInDB(String namePrefix, int count) {
|
||||||
|
return testdataFactory.createTargetTypes(namePrefix, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private TargetType createTestTargetTypeInDB(String name) {
|
||||||
|
return testdataFactory.findOrCreateTargetType(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private TargetType createTestTargetTypeInDB(String name, List<DistributionSetType> dsTypes) {
|
||||||
|
TargetType targetType = testdataFactory.createTargetType(name, dsTypes);
|
||||||
|
assertThat(targetType.getOptLockRevision()).isEqualTo(1);
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private List<TargetType> buildTestTargetTypesWithoutDsTypes(String namePrefix, int count) {
|
||||||
|
final List<TargetType> types = new ArrayList<>();
|
||||||
|
for (int index = 0; index < count; index++) {
|
||||||
|
types.add(buildTestTargetTypeBody(namePrefix + index));
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private void runPostTargetTypeAndVerify(final List<TargetType> types) throws Exception {
|
||||||
|
int size = types.size();
|
||||||
|
ResultActions resultActions = mvc
|
||||||
|
.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(types))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print());
|
||||||
|
|
||||||
|
for (int index = 0; index < size; index++) {
|
||||||
|
resultActions.andExpect(status().isCreated()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(jsonPath("$[" + index + "].id").exists())
|
||||||
|
.andExpect(jsonPath("$[" + index + "].name", startsWith("TestTypePOST")))
|
||||||
|
.andExpect(jsonPath("$[" + index + "].colour", hasToString("#aaaaaa")))
|
||||||
|
.andExpect(jsonPath("$[" + index + "].description",
|
||||||
|
equalTo("Description of the test type")))
|
||||||
|
.andExpect(jsonPath("$[" + index + "].createdBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$[" + index + "].createdAt").exists())
|
||||||
|
.andExpect(jsonPath("$[" + index + "].lastModifiedBy", equalTo(TEST_USER)))
|
||||||
|
.andExpect(jsonPath("$[" + index + "].lastModifiedAt").exists())
|
||||||
|
.andExpect(jsonPath("$[" + index + "].key").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$[" + index + "].deleted").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$[" + index + "]._links.self.href",
|
||||||
|
startsWith("http://localhost/rest/v1/targettypes/")))
|
||||||
|
.andExpect(
|
||||||
|
jsonPath("$[" + index + "]._links.compatibledistributionsettypes.href")
|
||||||
|
.doesNotExist());
|
||||||
|
}
|
||||||
|
MvcResult mvcResult = resultActions.andReturn();
|
||||||
|
|
||||||
|
for (int index = 0; index < size; index++) {
|
||||||
|
String name = "TestTypePOST" + index;
|
||||||
|
final TargetType created = targetTypeManagement.getByName(name).get();
|
||||||
|
|
||||||
|
assertThat(JsonPath.compile("$[ ?(@.name=='" + name + "') ].id")
|
||||||
|
.read(mvcResult.getResponse().getContentAsString()).toString()).contains(String.valueOf(created.getId()));
|
||||||
|
assertThat(JsonPath.compile("$[ ?(@.name=='" + name + "') ]._links.self.href")
|
||||||
|
.read(mvcResult.getResponse().getContentAsString()).toString()).contains("/"+created.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(targetTypeManagement.count()).isEqualTo(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -87,6 +87,7 @@ public class ResponseExceptionHandler {
|
|||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED, HttpStatus.FORBIDDEN);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED, HttpStatus.FORBIDDEN);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_MULTIASSIGNMENT_NOT_ENABLED, HttpStatus.BAD_REQUEST);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_MULTIASSIGNMENT_NOT_ENABLED, HttpStatus.BAD_REQUEST);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE, HttpStatus.BAD_REQUEST);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE, HttpStatus.BAD_REQUEST);
|
||||||
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_TARGET_TYPE_IN_USE, HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpStatus getStatusOrDefault(final SpServerError error) {
|
private static HttpStatus getStatusOrDefault(final SpServerError error) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
|||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||||
import org.eclipse.hawkbit.repository.model.Tag;
|
import org.eclipse.hawkbit.repository.model.Tag;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -426,13 +427,13 @@ public abstract class JsonBuilder {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
for (final Target target : targets) {
|
for (final Target target : targets) {
|
||||||
final String address = target.getAddress() != null ? target.getAddress().toString() : null;
|
final String address = target.getAddress() != null ? target.getAddress().toString() : null;
|
||||||
|
final String targetType = target.getTargetType() != null ? target.getTargetType().getId().toString() : null;
|
||||||
final String token = withToken ? target.getSecurityToken() : null;
|
final String token = withToken ? target.getSecurityToken() : null;
|
||||||
|
|
||||||
builder.append(new JSONObject().put("controllerId", target.getControllerId())
|
builder.append(new JSONObject().put("controllerId", target.getControllerId())
|
||||||
.put("description", target.getDescription()).put("name", target.getName()).put("createdAt", "0")
|
.put("description", target.getDescription()).put("name", target.getName()).put("createdAt", "0")
|
||||||
.put("updatedAt", "0").put("createdBy", "fghdfkjghdfkjh").put("updatedBy", "fghdfkjghdfkjh")
|
.put("updatedAt", "0").put("createdBy", "systemtest").put("updatedBy", "systemtest")
|
||||||
.put("address", address).put("securityToken", token).toString());
|
.put("address", address).put("securityToken", token).put("targetType", targetType).toString());
|
||||||
|
|
||||||
if (++i < targets.size()) {
|
if (++i < targets.size()) {
|
||||||
builder.append(",");
|
builder.append(",");
|
||||||
@@ -444,6 +445,83 @@ public abstract class JsonBuilder {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String targets(final List<Target> targets, final boolean withToken, final long targetTypeId) throws JSONException {
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
builder.append("[");
|
||||||
|
int i = 0;
|
||||||
|
for (final Target target : targets) {
|
||||||
|
final String address = target.getAddress() != null ? target.getAddress().toString() : null;
|
||||||
|
final String type = target.getTargetType() != null ? target.getTargetType().getId().toString() : null;
|
||||||
|
final String token = withToken ? target.getSecurityToken() : null;
|
||||||
|
|
||||||
|
builder.append(new JSONObject().put("controllerId", target.getControllerId())
|
||||||
|
.put("description", target.getDescription()).put("name", target.getName()).put("createdAt", "0")
|
||||||
|
.put("updatedAt", "0").put("createdBy", "fghdfkjghdfkjh").put("updatedBy", "fghdfkjghdfkjh")
|
||||||
|
.put("address", address).put("securityToken", token).put("targetType", targetTypeId).toString());
|
||||||
|
|
||||||
|
if (++i < targets.size()) {
|
||||||
|
builder.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append("]");
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String targetTypes(final List<TargetType> types) throws JSONException {
|
||||||
|
final JSONArray result = new JSONArray();
|
||||||
|
|
||||||
|
for (final TargetType type : types) {
|
||||||
|
|
||||||
|
final JSONArray dsTypes = new JSONArray();
|
||||||
|
type.getCompatibleDistributionSetTypes().forEach(dsType -> {
|
||||||
|
try {
|
||||||
|
dsTypes.put(new JSONObject().put("id", dsType.getId()));
|
||||||
|
} catch (final JSONException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
result.put(new JSONObject().put("name", type.getName()).put("description", type.getDescription())
|
||||||
|
.put("id", Long.MAX_VALUE).put("colour", type.getColour()).put("createdAt", "0").put("updatedAt", "0")
|
||||||
|
.put("createdBy", "fghdfkjghdfkjh").put("updatedBy", "fghdfkjghdfkjh")
|
||||||
|
.put("distributionsets", dsTypes));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String targetTypesCreatableFieldsOnly(final List<TargetType> types) throws JSONException {
|
||||||
|
final JSONArray result = new JSONArray();
|
||||||
|
|
||||||
|
for (final TargetType type : types) {
|
||||||
|
|
||||||
|
final JSONArray dsTypes = new JSONArray();
|
||||||
|
type.getCompatibleDistributionSetTypes().forEach(dsType -> {
|
||||||
|
try {
|
||||||
|
dsTypes.put(new JSONObject().put("id", dsType.getId()));
|
||||||
|
} catch (final JSONException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject().put("name", type.getName()).put("description", type.getDescription())
|
||||||
|
.put("colour", type.getColour());
|
||||||
|
|
||||||
|
if(dsTypes.length() != 0)
|
||||||
|
{
|
||||||
|
json.put("compatibledistributionsettypes", dsTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.put(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static String rollout(final String name, final String description, final int groupSize,
|
public static String rollout(final String name, final String description, final int groupSize,
|
||||||
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions) {
|
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions) {
|
||||||
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, null, null,
|
return rollout(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, null, null,
|
||||||
|
|||||||
@@ -0,0 +1,396 @@
|
|||||||
|
:doctype: book
|
||||||
|
:icons: font
|
||||||
|
:source-highlighter: highlightjs
|
||||||
|
:toc: macro
|
||||||
|
:toclevels: 1
|
||||||
|
:sectlinks:
|
||||||
|
:linkattrs:
|
||||||
|
|
||||||
|
[[target-types]]
|
||||||
|
= Target Types
|
||||||
|
|
||||||
|
toc::[]
|
||||||
|
|
||||||
|
|
||||||
|
== GET /rest/v1/targettypes
|
||||||
|
|
||||||
|
=== Implementation notes
|
||||||
|
|
||||||
|
Handles the GET request of retrieving all target types within Hawkbit. Required Permission: READ_TARGET
|
||||||
|
|
||||||
|
=== Get target types
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-types/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-types/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request query parameter
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-types-with-parameters/request-parameters.adoc[]
|
||||||
|
|
||||||
|
==== Request parameter example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-types-with-parameters/http-request.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 200)
|
||||||
|
|
||||||
|
==== Response fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-types/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-types/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
== POST /rest/v1/targettypes
|
||||||
|
|
||||||
|
=== Implementation notes
|
||||||
|
|
||||||
|
Handles the POST request for creating new target types within Hawkbit. The request body must always be a list of types. Required Permission: CREATE_TARGET
|
||||||
|
|
||||||
|
=== Create target types
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-target-types/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-target-types/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-target-types/request-fields.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 201)
|
||||||
|
|
||||||
|
==== Response fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-target-types/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-target-types/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
| `404 Not Found`
|
||||||
|
| Target type was not found.
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
| `409 Conflict`
|
||||||
|
| Target type already exists
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/415.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
== DELETE /rest/v1/targettypes/{targetTypeId}
|
||||||
|
|
||||||
|
=== Implementation Notes
|
||||||
|
|
||||||
|
Handles the DELETE request for a single target type within Hawkbit. Required Permission: DELETE_TARGET
|
||||||
|
|
||||||
|
=== Delete target type
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-target-type/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-target-type/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request path parameter
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-target-type/path-parameters.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 200)
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-target-type/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
| `404 Not Found`
|
||||||
|
| Target type was not found.
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
== GET /rest/v1/targettypes/{targetTypeId}
|
||||||
|
|
||||||
|
=== Implementation notes
|
||||||
|
|
||||||
|
Handles the GET request of retrieving a single target type within Hawkbit. Required Permission: READ_TARGET
|
||||||
|
|
||||||
|
=== Get target type
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-type/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-type/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request path parameter
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-type/path-parameters.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 200)
|
||||||
|
|
||||||
|
==== Response fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-type/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-target-type/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
| `404 Not Found`
|
||||||
|
| Target type was not found.
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
== PUT /rest/v1/targettypes/{targetTypeId}
|
||||||
|
|
||||||
|
=== Implementation notes
|
||||||
|
|
||||||
|
Handles the PUT request for a single target type within Hawkbit. Required Permission: UPDATE_TARGET
|
||||||
|
|
||||||
|
=== Update target type
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/put-target-type/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/put-target-type/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request path parameter
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/put-target-type/path-parameters.adoc[]
|
||||||
|
|
||||||
|
==== Request fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/put-target-type/request-fields.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 200)
|
||||||
|
|
||||||
|
==== Response fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/put-target-type/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/put-target-type/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
| `404 Not Found`
|
||||||
|
| Target type was not found.
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
include::../errors/409.adoc[]
|
||||||
|
include::../errors/415.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
== GET /rest/v1/targettypes/{targetTypeId}/compatibledistributionsettypes
|
||||||
|
|
||||||
|
=== Implementation notes
|
||||||
|
|
||||||
|
Handles the GET request of retrieving the list of compatible distribution set types in that target type. Required Permission: READ_TARGET, READ_REPOSITORY
|
||||||
|
|
||||||
|
=== Lists all compatible distribution set types
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-compatible-distribution-set-types/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-compatible-distribution-set-types/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request path parameter
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-compatible-distribution-set-types/path-parameters.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 200)
|
||||||
|
|
||||||
|
==== Response fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-compatible-distribution-set-types/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/get-compatible-distribution-set-types/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
| `404 Not Found`
|
||||||
|
| Distribution set type was not found.
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
== POST /rest/v1/targettypes/{targetTypeId}/compatibledistributionsettypes
|
||||||
|
|
||||||
|
=== Implementation notes
|
||||||
|
|
||||||
|
Handles the POST request for adding compatible distribution set types to a target type. Required Permission: UPDATE_TARGET and READ_REPOSITORY
|
||||||
|
|
||||||
|
=== Add compatible distribution set type
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-compatible-distribution-set-types/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-compatible-distribution-set-types/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request path parameter
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-compatible-distribution-set-types/path-parameters.adoc[]
|
||||||
|
|
||||||
|
==== Request fields
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-compatible-distribution-set-types/request-fields.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 201)
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/post-compatible-distribution-set-types/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
| `404 Not Found`
|
||||||
|
| Distribution set type was not found.
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
| `409 Conflict`
|
||||||
|
| Distribution set type already exists
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/415.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
== DELETE /rest/v1/targettypes/{targetTypeId}/compatibledistributionsettypes/{distributionSetTypeId}
|
||||||
|
|
||||||
|
=== Implementation Notes
|
||||||
|
|
||||||
|
Handles the DELETE request for removing a distribution set type from a single target type. Required Permission: UPDATE_TARGET and READ_REPOSITORY
|
||||||
|
|
||||||
|
=== Remove compatible distribution set type from target type
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-compatible-distribution-set-type/curl-request.adoc[]
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-compatible-distribution-set-type/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Request path parameter
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-compatible-distribution-set-type/path-parameters.adoc[]
|
||||||
|
|
||||||
|
=== Response (Status 200)
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/targettypes/delete-compatible-distribution-set-type/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
| `404 Not Found`
|
||||||
|
| Distribution set type was not found.
|
||||||
|
| See <<error-body>>
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
@@ -19,12 +19,12 @@ public final class ApiModelPropertiesGeneric {
|
|||||||
public static final String ITEM_ID = "The technical identifier " + ENDING;
|
public static final String ITEM_ID = "The technical identifier " + ENDING;
|
||||||
public static final String NAME = "The name" + ENDING;
|
public static final String NAME = "The name" + ENDING;
|
||||||
public static final String DESCRPTION = "The description" + ENDING;
|
public static final String DESCRPTION = "The description" + ENDING;
|
||||||
public static final String COLOUR = "The colour" + ENDING;
|
public static final String COLOUR = "The colour" + ENDING + ". In HEX format, e.g. #800080";
|
||||||
public static final String DELETED = "Deleted flag, used for soft deleted entities";
|
public static final String DELETED = "Deleted flag, used for soft deleted entities";
|
||||||
|
|
||||||
public static final String CREATED_BY = "Entity was originally created by User, AMQP-Controller, anonymous etc.)";
|
public static final String CREATED_BY = "Entity was originally created by (User, AMQP-Controller, anonymous etc.)";
|
||||||
public static final String CREATED_AT = "Entity was originally created at (timestamp UTC in milliseconds)";
|
public static final String CREATED_AT = "Entity was originally created at (timestamp UTC in milliseconds)";
|
||||||
public static final String LAST_MODIFIED_BY = "Entity was last modified by User, AMQP-Controller, anonymous etc.)";
|
public static final String LAST_MODIFIED_BY = "Entity was last modified by (User, AMQP-Controller, anonymous etc.)";
|
||||||
public static final String LAST_MODIFIED_AT = "Entity was last modified at (timestamp UTC in milliseconds)";
|
public static final String LAST_MODIFIED_AT = "Entity was last modified at (timestamp UTC in milliseconds)";
|
||||||
|
|
||||||
// Paging elements
|
// Paging elements
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ public final class MgmtApiModelProperties {
|
|||||||
public static final String POLL_STATUS = "Poll status of the target. In many scenarios that target will poll the update server on a regular basis to look for potential updates. If that poll does not happen it might imply that the target is offline.";
|
public static final String POLL_STATUS = "Poll status of the target. In many scenarios that target will poll the update server on a regular basis to look for potential updates. If that poll does not happen it might imply that the target is offline.";
|
||||||
public static final String POLL_OVERDUE = "Defines if the target poll time is overdue based on the next expected poll time plus the configured overdue poll time threshold.";
|
public static final String POLL_OVERDUE = "Defines if the target poll time is overdue based on the next expected poll time plus the configured overdue poll time threshold.";
|
||||||
|
|
||||||
|
// Target type
|
||||||
|
public static final String COMPATIBLE_DS_TYPES = "Array of distribution set types that are compatible to that target type";
|
||||||
|
public static final String LINK_COMPATIBLE_DS_TYPES = "Link to the compatible distribution set types in this target type";
|
||||||
|
|
||||||
// rollout
|
// rollout
|
||||||
public static final String ROLLOUT_FILTER_QUERY = "target filter query language expression";
|
public static final String ROLLOUT_FILTER_QUERY = "target filter query language expression";
|
||||||
public static final String ROLLOUT_GROUP_FILTER_QUERY = "target filter query language expression that selects a subset of targets which match the target filter of the Rollout";
|
public static final String ROLLOUT_GROUP_FILTER_QUERY = "target filter query language expression that selects a subset of targets which match the target filter of the Rollout";
|
||||||
@@ -118,6 +122,8 @@ public final class MgmtApiModelProperties {
|
|||||||
|
|
||||||
public static final String TARGET_LIST = "List of provisioning targets.";
|
public static final String TARGET_LIST = "List of provisioning targets.";
|
||||||
|
|
||||||
|
public static final String TARGET_TYPE_LIST = "List of target types";
|
||||||
|
|
||||||
public static final String SM_LIST = "List of software modules.";
|
public static final String SM_LIST = "List of software modules.";
|
||||||
|
|
||||||
public static final String ROLLOUT_LIST = "list of rollouts";
|
public static final String ROLLOUT_LIST = "list of rollouts";
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
/**
|
||||||
|
* 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.rest.mgmt.documentation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.qameta.allure.Description;
|
||||||
|
import io.qameta.allure.Feature;
|
||||||
|
import io.qameta.allure.Story;
|
||||||
|
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||||
|
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||||
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
|
||||||
|
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
|
||||||
|
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
|
||||||
|
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||||
|
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.restdocs.payload.JsonFieldType;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
|
||||||
|
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||||
|
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
|
||||||
|
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Documentation generation for Management API for {@link TargetType}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Feature("Spring Rest Docs Tests - TargetType")
|
||||||
|
@Story("TargetTypes Resource")
|
||||||
|
public class TargetTypesDocumentationTest extends AbstractApiRestDocumentation {
|
||||||
|
@Override
|
||||||
|
public String getResourceName() {
|
||||||
|
return "targettypes";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the GET request of retrieving all target types within Hawkbit. Required Permission: "
|
||||||
|
+ SpPermission.READ_TARGET)
|
||||||
|
public void getTargetTypes() throws Exception {
|
||||||
|
testdataFactory.findOrCreateTargetType("targetType1");
|
||||||
|
testdataFactory.createTargetType("targetType2", Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mockMvc.perform(get(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andDo(this.document.document(responseFields(
|
||||||
|
fieldWithPath("size").type(JsonFieldType.NUMBER).description(ApiModelPropertiesGeneric.SIZE),
|
||||||
|
fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
|
||||||
|
fieldWithPath("content").description(MgmtApiModelProperties.TARGET_TYPE_LIST),
|
||||||
|
fieldWithPath("content[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||||
|
fieldWithPath("content[].name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
|
fieldWithPath("content[].description").description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
|
fieldWithPath("content[].colour").description(ApiModelPropertiesGeneric.COLOUR),
|
||||||
|
fieldWithPath("content[].createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
|
||||||
|
fieldWithPath("content[].createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
|
||||||
|
fieldWithPath("content[].lastModifiedAt")
|
||||||
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
|
||||||
|
fieldWithPath("content[].lastModifiedBy")
|
||||||
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
|
||||||
|
fieldWithPath("content[]._links.self").ignored())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the GET request of retrieving all target types within Hawkbit with a defined page size and "
|
||||||
|
+ "offset, sorted by name in descending order and filtered down to all targets which name starts with 'targetType'. "
|
||||||
|
+ "Required Permission: " + SpPermission.READ_TARGET)
|
||||||
|
public void getTargetTypesWithParameters() throws Exception {
|
||||||
|
testdataFactory.findOrCreateTargetType("targetType1");
|
||||||
|
testdataFactory.createTargetType("targetType2", Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mockMvc.perform(get(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON)
|
||||||
|
.param("offset", "0").param("limit", "2").param("sort", "name:ASC").param("q", "name==targetType*"))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(this.document.document(getFilterRequestParamter()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the GET request for a single target type within Hawkbit. Required Permission: "
|
||||||
|
+ SpPermission.READ_TARGET)
|
||||||
|
public void getTargetType() throws Exception {
|
||||||
|
TargetType testType = testdataFactory.createTargetType("TargetType", Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mockMvc.perform(get(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING + "/{targetTypeId}", testType.getId())
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andDo(this.document.document(
|
||||||
|
pathParameters(
|
||||||
|
parameterWithName("targetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||||
|
responseFields(fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||||
|
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
|
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
|
fieldWithPath("colour").description(ApiModelPropertiesGeneric.COLOUR),
|
||||||
|
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
|
||||||
|
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
|
||||||
|
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
|
||||||
|
.type("Number"),
|
||||||
|
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
|
||||||
|
.type("String"),
|
||||||
|
fieldWithPath("_links.compatibledistributionsettypes.href")
|
||||||
|
.description(MgmtApiModelProperties.LINK_COMPATIBLE_DS_TYPES),
|
||||||
|
fieldWithPath("_links.self").ignored())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the POST request for creating new target types within Hawkbit. The request body "
|
||||||
|
+ "must always be a list of types. Required Permission: " + SpPermission.CREATE_TARGET)
|
||||||
|
public void postTargetTypes() throws Exception {
|
||||||
|
final List<TargetType> types = new ArrayList<>();
|
||||||
|
types.add(entityFactory.targetType().create().name("targetType1").description("targetType1 description")
|
||||||
|
.colour("#ffffff").build());
|
||||||
|
types.add(entityFactory.targetType().create().name("targetType2").description("targetType2 description")
|
||||||
|
.colour("#000000").compatible(Collections.singletonList(standardDsType.getId())).build());
|
||||||
|
|
||||||
|
mockMvc.perform(post(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING)
|
||||||
|
.content(JsonBuilder.targetTypesCreatableFieldsOnly(types)).contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||||
|
.andDo(this.document.document(
|
||||||
|
requestFields(requestFieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
|
optionalRequestFieldWithPath("[]description")
|
||||||
|
.description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
|
optionalRequestFieldWithPath("[]colour").description(ApiModelPropertiesGeneric.COLOUR),
|
||||||
|
optionalRequestFieldWithPath("[]compatibledistributionsettypes")
|
||||||
|
.description(MgmtApiModelProperties.COMPATIBLE_DS_TYPES)),
|
||||||
|
responseFields(fieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||||
|
fieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
|
fieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
|
fieldWithPath("[]colour").description(ApiModelPropertiesGeneric.COLOUR),
|
||||||
|
fieldWithPath("[]createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
|
||||||
|
fieldWithPath("[]createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
|
||||||
|
fieldWithPath("[]lastModifiedAt")
|
||||||
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
|
||||||
|
fieldWithPath("[]lastModifiedBy")
|
||||||
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
|
||||||
|
fieldWithPath("[]_links.self").ignored())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the DELETE request of retrieving a single target type within Hawkbit. Required Permission: "
|
||||||
|
+ SpPermission.DELETE_TARGET)
|
||||||
|
public void deleteTargetType() throws Exception {
|
||||||
|
TargetType testType = testdataFactory.createTargetType("TargetType", Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mockMvc.perform(delete(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING + "/{targetTypeId}", testType.getId()))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andDo(this.document.document(pathParameters(
|
||||||
|
parameterWithName("targetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the PUT request for a single target type within Hawkbit. " + "Required Permission: "
|
||||||
|
+ SpPermission.UPDATE_TARGET)
|
||||||
|
public void putTargetType() throws Exception {
|
||||||
|
TargetType testType = testdataFactory.createTargetType("targetType", Collections.singletonList(standardDsType));
|
||||||
|
final String body = new JSONObject().put("description", "an updated description").put("name", "updatedTypeName")
|
||||||
|
.put("colour", "#aaafff").toString();
|
||||||
|
|
||||||
|
this.mockMvc
|
||||||
|
.perform(put(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING + "/{targetTypeId}", testType.getId())
|
||||||
|
.content(body).contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andDo(this.document.document(
|
||||||
|
pathParameters(
|
||||||
|
parameterWithName("targetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||||
|
requestFields(
|
||||||
|
optionalRequestFieldWithPath("description")
|
||||||
|
.description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
|
optionalRequestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
|
optionalRequestFieldWithPath("colour").description(ApiModelPropertiesGeneric.COLOUR)),
|
||||||
|
responseFields(fieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||||
|
fieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
|
fieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
|
fieldWithPath("colour").description(ApiModelPropertiesGeneric.COLOUR),
|
||||||
|
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
|
||||||
|
fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
|
||||||
|
fieldWithPath("lastModifiedAt").description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT)
|
||||||
|
.type("Number"),
|
||||||
|
fieldWithPath("lastModifiedBy").description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY)
|
||||||
|
.type("String"),
|
||||||
|
fieldWithPath("_links.compatibledistributionsettypes.href")
|
||||||
|
.description(MgmtApiModelProperties.LINK_COMPATIBLE_DS_TYPES),
|
||||||
|
fieldWithPath("_links.self").ignored())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the GET request of retrieving the list of compatible distribution set types in that target type. "
|
||||||
|
+ "Required Permission: " + SpPermission.READ_TARGET + " and " + SpPermission.READ_REPOSITORY)
|
||||||
|
public void getCompatibleDistributionSetTypes() throws Exception {
|
||||||
|
TargetType testType = testdataFactory.createTargetType("targetType", Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
get(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING + "/{targetTypeId}/compatibledistributionsettypes",
|
||||||
|
testType.getId()).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||||
|
|
||||||
|
.andDo(this.document.document(
|
||||||
|
pathParameters(
|
||||||
|
parameterWithName("targetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||||
|
responseFields(fieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||||
|
fieldWithPath("[]key").description(MgmtApiModelProperties.DS_TYPE_KEY),
|
||||||
|
fieldWithPath("[]name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
|
fieldWithPath("[]description").description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
|
fieldWithPath("[]createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
|
||||||
|
fieldWithPath("[]createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
|
||||||
|
fieldWithPath("[]lastModifiedAt")
|
||||||
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
|
||||||
|
fieldWithPath("[]lastModifiedBy")
|
||||||
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_BY).type("String"),
|
||||||
|
fieldWithPath("[]deleted").description(ApiModelPropertiesGeneric.DELETED),
|
||||||
|
fieldWithPath("[]_links.self").ignored())));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the POST request for adding a compatible distribution set type to a target type."
|
||||||
|
+ " Required Permission: " + SpPermission.UPDATE_TARGET + " and " + SpPermission.READ_REPOSITORY)
|
||||||
|
public void postCompatibleDistributionSetTypes() throws Exception {
|
||||||
|
final DistributionSetType dsType1 = distributionSetTypeManagement.create(
|
||||||
|
entityFactory.distributionSetType().create().key("test1").name("TestName1").description("Desc1"));
|
||||||
|
final DistributionSetType dsType2 = distributionSetTypeManagement.create(
|
||||||
|
entityFactory.distributionSetType().create().key("test2").name("TestName2").description("Desc2"));
|
||||||
|
final TargetType targetType = testdataFactory.createTargetType("targetType",
|
||||||
|
Collections.singletonList(standardDsType));
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
post(MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING + "/{targetTypeId}/compatibledistributionsettypes",
|
||||||
|
targetType.getId())
|
||||||
|
.content("[{\"id\":" + dsType1.getId() + "},{\"id\":" + dsType2.getId() + "}]")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andDo(this.document.document(
|
||||||
|
pathParameters(
|
||||||
|
parameterWithName("targetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||||
|
requestFields(requestFieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the DELETE request to unassign the list of compatible distribution set types in that target type. "
|
||||||
|
+ SpPermission.UPDATE_TARGET + " and " + SpPermission.READ_REPOSITORY)
|
||||||
|
public void deleteCompatibleDistributionSetType() throws Exception {
|
||||||
|
final DistributionSetType dsType = distributionSetTypeManagement.create(
|
||||||
|
entityFactory.distributionSetType().create().key("test1").name("TestName1").description("Desc1"));
|
||||||
|
final TargetType targetType = testdataFactory.createTargetType("targetType", Collections.singletonList(dsType));
|
||||||
|
|
||||||
|
mockMvc.perform(delete(
|
||||||
|
MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING
|
||||||
|
+ "/{targetTypeId}/compatibledistributionsettypes/{distributionSetTypeId}",
|
||||||
|
targetType.getId(), dsType.getId()).contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andDo(this.document.document(pathParameters(
|
||||||
|
parameterWithName("targetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||||
|
parameterWithName("distributionSetTypeId").description(ApiModelPropertiesGeneric.ITEM_ID))));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -298,6 +298,11 @@ public class HawkbitSecurityProperties {
|
|||||||
*/
|
*/
|
||||||
private long maxArtifactStorage = 21_474_836_480L;
|
private long maxArtifactStorage = 21_474_836_480L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of distribution set types per target types
|
||||||
|
*/
|
||||||
|
private int maxDistributionSetTypesPerTargetType = 50;
|
||||||
|
|
||||||
private final Filter filter = new Filter();
|
private final Filter filter = new Filter();
|
||||||
private final Filter uiFilter = new Filter();
|
private final Filter uiFilter = new Filter();
|
||||||
|
|
||||||
@@ -439,6 +444,10 @@ public class HawkbitSecurityProperties {
|
|||||||
this.maxArtifactStorage = maxArtifactStorage;
|
this.maxArtifactStorage = maxArtifactStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxDistributionSetTypesPerTargetType() {
|
||||||
|
return maxDistributionSetTypesPerTargetType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for hawkBits DOS prevention filter. This is usually an
|
* Configuration for hawkBits DOS prevention filter. This is usually an
|
||||||
* infrastructure topic (e.g. Web Application Firewall (WAF)) but might
|
* infrastructure topic (e.g. Web Application Firewall (WAF)) but might
|
||||||
|
|||||||
Reference in New Issue
Block a user