Dmf batch support changes. (#1273)

* Dmf batch support changes. Implement single batch message instead of multiple messages for assigment on multiple targets. Added system property to switch on/off.

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>

* Dmf batch support changes. Implement single batch message instead of multiple messages for assigment on multiple targets. Added system property to switch on/off.

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>

* Dmf batch support changes. Implement single batch message instead of multiple messages for assigment on multiple targets. Added system property to switch on/off.

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>

* Dmf batch support changes. Implement single batch message instead of multiple messages for assigment on multiple targets. Added system property to switch on/off.

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>

* Update hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java

Co-authored-by: Bondar Bogdan <36962546+bogdan-bondar@users.noreply.github.com>

* Dmf batch support changes. Implement single batch message instead of multiple messages for assigment on multiple targets. Added system property to switch on/off.

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>

* Dmf batch support changes. Implement single batch message instead of multiple messages for assigment on multiple targets. Added system property to switch on/off.

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>

* Dmf batch support changes. Implement code review comments.

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>

Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>
Co-authored-by: Bondar Bogdan <36962546+bogdan-bondar@users.noreply.github.com>
This commit is contained in:
Dimitar Shterev
2022-08-30 10:55:52 +03:00
committed by GitHub
parent ccb5fa3b3f
commit bc2f228edc
13 changed files with 406 additions and 19 deletions

View File

@@ -354,10 +354,11 @@ public class AmqpConfiguration {
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
final SoftwareModuleManagement softwareModuleManagement, final DeploymentManagement deploymentManagement) {
final SoftwareModuleManagement softwareModuleManagement, final DeploymentManagement deploymentManagement,
final TenantConfigurationManagement tenantConfigurationManagement) {
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
systemSecurityContext, systemManagement, targetManagement, serviceMatcher, distributionSetManagement,
softwareModuleManagement, deploymentManagement);
softwareModuleManagement, deploymentManagement, tenantConfigurationManagement);
}
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.amqp;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED;
import java.net.URI;
import java.util.Collections;
@@ -32,16 +33,19 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfArtifact;
import org.eclipse.hawkbit.dmf.json.model.DmfArtifactHash;
import org.eclipse.hawkbit.dmf.json.model.DmfBatchDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.event.remote.MultiActionEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
@@ -89,6 +93,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private final DistributionSetManagement distributionSetManagement;
private final DeploymentManagement deploymentManagement;
private final SoftwareModuleManagement softwareModuleManagement;
private final TenantConfigurationManagement tenantConfigurationManagement;
/**
* Constructor.
@@ -110,13 +115,17 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* cluster node
* @param distributionSetManagement
* to retrieve modules
* @param tenantConfigurationManagement
* to access tenant configuration
*
*/
protected AmqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher,
final DistributionSetManagement distributionSetManagement,
final SoftwareModuleManagement softwareModuleManagement, final DeploymentManagement deploymentManagement) {
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher,
final DistributionSetManagement distributionSetManagement,
final SoftwareModuleManagement softwareModuleManagement, final DeploymentManagement deploymentManagement,
final TenantConfigurationManagement tenantConfigurationManagement) {
super(rabbitTemplate);
this.artifactUrlHandler = artifactUrlHandler;
this.amqpSenderService = amqpSenderService;
@@ -127,6 +136,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
this.distributionSetManagement = distributionSetManagement;
this.softwareModuleManagement = softwareModuleManagement;
this.deploymentManagement = deploymentManagement;
this.tenantConfigurationManagement = tenantConfigurationManagement;
}
/**
@@ -182,8 +192,13 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
distributionSetManagement.get(assignedEvent.getDistributionSetId()).ifPresent(ds -> {
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules = getSoftwareModulesWithMetadata(
ds);
targets.forEach(target -> sendUpdateMessageToTarget(
assignedEvent.getActions().get(target.getControllerId()), target, softwareModules));
if (!targets.isEmpty() && isBatchAssignmentsEnabled()) {
sendUpdateMessageToTargets(assignedEvent.getActions(), targets, softwareModules);
} else {
targets.forEach(target -> sendUpdateMessageToTarget(
assignedEvent.getActions().get(target.getControllerId()), target, softwareModules));
}
});
}
@@ -500,4 +515,59 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), module.getId()).getContent();
}
private void sendUpdateMessageToTargets(final Map<String, ActionProperties> actions, final List<Target> targets,
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
List<DmfTarget> dmfTargets = targets.stream().filter(target -> IpUtil.isAmqpUri(target.getAddress()))
.map(t -> convertToDmfTarget(t, actions.get(t.getControllerId()).getId())).collect(Collectors.toList());
final DmfBatchDownloadAndUpdateRequest batchRequest = new DmfBatchDownloadAndUpdateRequest();
batchRequest.setTimestamp(System.currentTimeMillis());
batchRequest.addTargets(dmfTargets);
//due to the fact that all targets in a batch use the same set of software modules we don't generate
// target-specific urls
Target firstTarget = targets.get(0);
if (modules != null) {
modules.entrySet().forEach(entry ->
batchRequest.addSoftwareModule(convertToAmqpSoftwareModule(firstTarget, entry)));
}
// we use only the first action when constructing message as Tenant and action type are the same
// since all actions have the same trigger
final ActionProperties firstAction = actions.values().iterator().next();
final Message message = getMessageConverter().toMessage(batchRequest,
createMessagePropertiesBatch(firstAction.getTenant(), getBatchEventTopicForAction(firstAction)));
amqpSenderService.sendMessage(message, firstTarget.getAddress());
}
protected DmfTarget convertToDmfTarget(final Target target, final Long actionId) {
DmfTarget dmfTarget = new DmfTarget();
dmfTarget.setActionId(actionId);
dmfTarget.setControllerId(target.getControllerId());
dmfTarget.setTargetSecurityToken(systemSecurityContext.runAsSystem(target::getSecurityToken));
return dmfTarget;
}
private static MessageProperties createMessagePropertiesBatch(final String tenant, final EventTopic topic) {
final MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
messageProperties.setHeader(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON);
messageProperties.setHeader(MessageHeaderKey.TENANT, tenant);
messageProperties.setHeader(MessageHeaderKey.TOPIC, topic);
messageProperties.setHeader(MessageHeaderKey.TYPE, MessageType.EVENT);
return messageProperties;
}
public boolean isBatchAssignmentsEnabled() {
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
.getConfigurationValue(BATCH_ASSIGNMENTS_ENABLED, Boolean.class).getValue());
}
private static EventTopic getBatchEventTopicForAction(final ActionProperties action) {
return (Action.ActionType.DOWNLOAD_ONLY == action.getActionType() || !action.isMaintenanceWindowAvailable())
? EventTopic.BATCH_DOWNLOAD
: EventTopic.BATCH_DOWNLOAD_AND_INSTALL;
}
}

View File

@@ -111,7 +111,7 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement, serviceMatcher,
distributionSetManagement, softwareModuleManagement, deploymentManagement);
distributionSetManagement, softwareModuleManagement, deploymentManagement, tenantConfigurationManagement);
}

View File

@@ -12,7 +12,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -32,6 +34,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate;
import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.integration.listener.DeadletterListener;
import org.eclipse.hawkbit.integration.listener.ReplyToListener;
import org.eclipse.hawkbit.matcher.SoftwareModuleJsonMatcher;
@@ -95,7 +98,7 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
getDmfClient().setExchange(AmqpSettings.DMF_EXCHANGE);
}
private <T> T waitUntilIsPresent(final Callable<Optional<T>> callable) {
protected <T> T waitUntilIsPresent(final Callable<Optional<T>> callable) {
createConditionFactory()
.until(() -> WithSpringAuthorityRule.runAsPrivileged(() -> callable.call().isPresent()));
@@ -194,10 +197,7 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
protected void assertDmfDownloadAndUpdateRequest(final DmfDownloadAndUpdateRequest request,
final Set<SoftwareModule> softwareModules, final String controllerId) {
assertThat(softwareModules)
.is(new HamcrestCondition<>(SoftwareModuleJsonMatcher.containsExactly(request.getSoftwareModules())));
request.getSoftwareModules().forEach(dmfModule -> assertThat(dmfModule.getMetadata()).containsExactly(
new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE)));
assertSoftwareModules(softwareModules, request.getSoftwareModules());
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.getByControllerID(controllerId));
assertThat(updatedTarget).isNotNull();
assertThat(updatedTarget.getSecurityToken()).isEqualTo(request.getTargetSecurityToken());
@@ -445,4 +445,11 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
return distributionSet;
}
protected void assertSoftwareModules(final Set<SoftwareModule> expectedSoftwareModules,
final List<DmfSoftwareModule> softwareModules) {
assertThat(expectedSoftwareModules)
.is(new HamcrestCondition<>(SoftwareModuleJsonMatcher.containsExactly(softwareModules)));
softwareModules.forEach(dmfModule -> assertThat(dmfModule.getMetadata()).containsExactly(
new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE)));
}
}

View File

@@ -9,9 +9,13 @@
package org.eclipse.hawkbit.integration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.BATCH_DOWNLOAD;
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.BATCH_DOWNLOAD_AND_INSTALL;
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.DOWNLOAD;
import static org.eclipse.hawkbit.dmf.amqp.api.MessageType.EVENT;
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
import static org.eclipse.hawkbit.repository.model.Action.ActionType.FORCED;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
@@ -29,10 +33,12 @@ import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus;
import org.eclipse.hawkbit.dmf.json.model.DmfBatchDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest.DmfMultiActionElement;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
@@ -53,6 +59,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedE
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationCreatedEvent;
import org.eclipse.hawkbit.repository.exception.TenantConfigurationValueChangeNotAllowedException;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -66,6 +73,8 @@ import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.mockito.Mockito;
import org.springframework.amqp.core.Message;
@@ -603,4 +612,87 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
|| multiActionElement.getTopic().equals(EventTopic.DOWNLOAD_AND_INSTALL);
}
@Test
@Description("Verify payload of batch assignment download and install message.")
public void assertBatchAssignmentsDownloadAndInstall() {
assertBatchAssignmentsMessagePayload(BATCH_DOWNLOAD_AND_INSTALL);
}
@Test
@Description("Verify payload of batch assignments download only message.")
public void assertBatchAssignmentsDownloadOnly() {
assertBatchAssignmentsMessagePayload(BATCH_DOWNLOAD);
}
@Test
@Description("Verify that batch and multi-assignments can't be activated at the same time.")
void assertBatchAndMultiAssignmentsNotCompatible() {
enableBatchAssignments();
assertThatExceptionOfType(TenantConfigurationValueChangeNotAllowedException.class)
.isThrownBy(() -> enableMultiAssignments());
disableBatchAssignments();
enableMultiAssignments();
assertThatExceptionOfType(TenantConfigurationValueChangeNotAllowedException.class)
.isThrownBy(() -> enableBatchAssignments());
}
@ParameterizedTest
@EnumSource(names = { "BATCH_DOWNLOAD_AND_INSTALL", "BATCH_DOWNLOAD" })
@Description("Verify payload of batch assignments.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 3), @Expect(type = ActionUpdatedEvent.class, count = 0),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 3), @Expect(type = TargetPollEvent.class, count = 3),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void assertBatchAssignmentsMessagePayload(final EventTopic topic) {
enableBatchAssignments();
final List<String> targets = Arrays.asList("batchCtrlID1", "batchCtrlID2", "batchCtrlID3");
for (int i = 0; i < targets.size(); i++) {
registerAndAssertTargetWithExistingTenant(targets.get(i), i+1);
}
final DistributionSet ds = testdataFactory.createDistributionSet();
testdataFactory.addSoftwareModuleMetadata(ds);
assignDistributionSet(ds.getId(), targets, topic == BATCH_DOWNLOAD?DOWNLOAD_ONLY:FORCED);
waitUntilEventMessagesAreDispatchedToTarget(topic);
final Message message = replyToListener.getLatestEventMessage(topic);
final Map<String, Object> headers = message.getMessageProperties().getHeaders();
assertThat(headers).containsEntry("type", EVENT.toString());
assertThat(headers).containsEntry("topic",topic.toString());
final DmfBatchDownloadAndUpdateRequest batchRequest = (DmfBatchDownloadAndUpdateRequest) getDmfClient()
.getMessageConverter().fromMessage(message);
assertThat(batchRequest).isExactlyInstanceOf(DmfBatchDownloadAndUpdateRequest.class);
assertDmfBatchDownloadAndUpdateRequest(batchRequest, ds.getModules(), targets);
}
protected void assertDmfBatchDownloadAndUpdateRequest(final DmfBatchDownloadAndUpdateRequest request,
final Set<SoftwareModule> softwareModules,
final List<String> controllerIds) {
assertSoftwareModules(softwareModules, request.getSoftwareModules());
List<Object> tokens = controllerIds.stream().map(controllerId -> {
final Optional<Target> target = controllerManagement.getByControllerId(controllerId);
assertThat(target).isPresent();
return target.get().getSecurityToken();
}).collect(Collectors.toList());
List<DmfTarget> requestTargets = request.getTargets();
assertThat(requestTargets).hasSameSizeAs(controllerIds);
requestTargets.forEach(requestTarget -> {
assertThat(requestTarget).isNotNull();
assertThat(tokens.contains(requestTarget.getTargetSecurityToken()));
});
}
}

View File

@@ -46,6 +46,16 @@ public enum EventTopic {
/**
* Topic to send multiple actions to the device.
*/
MULTI_ACTION
MULTI_ACTION,
/**
* Topic when sending a download only action to multiple devices.
*/
BATCH_DOWNLOAD,
/**
* Topic when sending a download and install action to multiple devices.
*/
BATCH_DOWNLOAD_AND_INSTALL
}

View File

@@ -0,0 +1,102 @@
/**
* Copyright (c) 2022 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.dmf.json.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* JSON representation of batch download and update request.
*
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class DmfBatchDownloadAndUpdateRequest {
@JsonProperty
private Long timestamp;
@JsonProperty
private List<DmfTarget> targets;
@JsonProperty
private List<DmfSoftwareModule> softwareModules;
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(final Long timestamp) {
this.timestamp = timestamp;
}
public List<DmfSoftwareModule> getSoftwareModules() {
if (softwareModules == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(softwareModules);
}
/**
* Add a Software module.
*
* @param createSoftwareModule
* the module
*/
public void addSoftwareModule(final DmfSoftwareModule createSoftwareModule) {
if (softwareModules == null) {
softwareModules = new ArrayList<>();
}
softwareModules.add(createSoftwareModule);
}
public List<DmfTarget> getTargets() {
if (targets == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(targets);
}
/**
* Add a Target.
*
* @param target
* the target
*/
public void addTarget(final DmfTarget target) {
if (targets == null) {
targets = new ArrayList<>();
}
targets.add(target);
}
/**
* Add multiple Targets.
*
* @param targets
* the target
*/
public void addTargets(final List<DmfTarget> targets) {
if (this.targets == null) {
this.targets = new ArrayList<>();
}
this.targets.addAll(targets);
}
}

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2022 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.dmf.json.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Json representation of Target used in batch download and update request.
*
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class DmfTarget {
@JsonProperty
private Long actionId;
@JsonProperty
private String controllerId;
@JsonProperty
private String targetSecurityToken;
public Long getActionId() {
return actionId;
}
public void setActionId(final Long actionId) {
this.actionId = actionId;
}
public String getControllerId() {
return controllerId;
}
public void setControllerId(final String controllerId) {
this.controllerId = controllerId;
}
public String getTargetSecurityToken() {
return targetSecurityToken;
}
public void setTargetSecurityToken(final String targetSecurityToken) {
this.targetSecurityToken = targetSecurityToken;
}
@Override
public String toString() {
return String.format(
"DmfTarget [actionId=%d controllerId='%s']",
actionId, controllerId);
}
}