Propose SDK Refactor (#1821)
* Propose SDK Refactor * Added ExecutorService for DMF Devices * After review, Created MgmtApi inside sdk-mgmt * Removed direct dependency to halkbit-mgmt-api all mgmt related calls now goes through hawkbit-sdk-mgmt * Added copyright header * Removed redundant paramters for deleteController * Fixed File Copyright Headers
This commit is contained in:
@@ -23,10 +23,7 @@
|
|||||||
<name>hawkBit :: SDK :: Commons</name>
|
<name>hawkBit :: SDK :: Commons</name>
|
||||||
<description>SDK commons</description>
|
<description>SDK commons</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<spring-cloud-starter-openfeign.version>4.1.0</spring-cloud-starter-openfeign.version>
|
|
||||||
<openfeign-hc5.version>13.2.1</openfeign-hc5.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -39,7 +36,6 @@
|
|||||||
<artifactId>feign-hc5</artifactId>
|
<artifactId>feign-hc5</artifactId>
|
||||||
<version>${openfeign-hc5.version}</version>
|
<version>${openfeign-hc5.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-hateoas</artifactId>
|
<artifactId>spring-boot-starter-hateoas</artifactId>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
<artifactId>hawkbit-mgmt-api</artifactId>
|
<artifactId>hawkbit-sdk-mgmt</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@@ -15,25 +15,22 @@ import feign.codec.Decoder;
|
|||||||
import feign.codec.Encoder;
|
import feign.codec.Encoder;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.sdk.Controller;
|
import org.eclipse.hawkbit.sdk.Controller;
|
||||||
import org.eclipse.hawkbit.sdk.HawkbitServer;
|
|
||||||
import org.eclipse.hawkbit.sdk.HawkbitClient;
|
import org.eclipse.hawkbit.sdk.HawkbitClient;
|
||||||
import org.eclipse.hawkbit.sdk.HawkbitSDKConfigurtion;
|
import org.eclipse.hawkbit.sdk.HawkbitServer;
|
||||||
import org.eclipse.hawkbit.sdk.Tenant;
|
import org.eclipse.hawkbit.sdk.Tenant;
|
||||||
import org.eclipse.hawkbit.sdk.demo.SetupHelper;
|
|
||||||
import org.eclipse.hawkbit.sdk.device.DdiController;
|
import org.eclipse.hawkbit.sdk.device.DdiController;
|
||||||
|
import org.eclipse.hawkbit.sdk.device.DdiTenant;
|
||||||
import org.eclipse.hawkbit.sdk.device.UpdateHandler;
|
import org.eclipse.hawkbit.sdk.device.UpdateHandler;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.eclipse.hawkbit.sdk.mgmt.MgmtApi;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.shell.standard.ShellComponent;
|
import org.springframework.shell.standard.ShellComponent;
|
||||||
import org.springframework.shell.standard.ShellMethod;
|
import org.springframework.shell.standard.ShellMethod;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class representing DDI device connecting directly to hawkVit.
|
* Abstract class representing DDI device connecting directly to hawkVit.
|
||||||
@@ -54,49 +51,49 @@ public class DeviceApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
DdiController device(
|
DdiTenant ddiTenant(final Tenant defaultTenant,
|
||||||
@Value("${hawkbit.device:controller-default}") final String controllerId,
|
final HawkbitClient hawkbitClient) {
|
||||||
@Value("${hawkbit.device.securityToken:}") final String securityToken,
|
return new DdiTenant(defaultTenant, hawkbitClient);
|
||||||
final Tenant defaultTenant,
|
}
|
||||||
final Optional<UpdateHandler> updateHandler,
|
|
||||||
final HawkbitClient hawkbitClient) {
|
@Bean
|
||||||
return new DdiController(
|
MgmtApi mgmtApi(final Tenant tenant, final HawkbitClient hawkbitClient) {
|
||||||
defaultTenant,
|
return new MgmtApi(tenant, hawkbitClient);
|
||||||
Controller.builder()
|
|
||||||
.controllerId(controllerId)
|
|
||||||
.securityToken(ObjectUtils.isEmpty(securityToken) ?
|
|
||||||
(ObjectUtils.isEmpty(defaultTenant.getGatewayToken()) ? SetupHelper.randomToken() : securityToken) :
|
|
||||||
securityToken)
|
|
||||||
.build(),
|
|
||||||
updateHandler.orElse(null),
|
|
||||||
hawkbitClient).setOverridePollMillis(10_000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellComponent
|
@ShellComponent
|
||||||
public static class Shell {
|
public static class Shell {
|
||||||
|
|
||||||
private final Tenant tenant;
|
private final DdiTenant ddiTenant;
|
||||||
|
|
||||||
private final DdiController device;
|
private final DdiController device;
|
||||||
private final HawkbitClient hawkbitClient;
|
private final MgmtApi mgmtApi;
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
|
|
||||||
Shell(final Tenant tenant, final DdiController device, final HawkbitClient hawkbitClient) {
|
Shell(final DdiTenant ddiTenant, final MgmtApi mgmtApi, final Optional<UpdateHandler> updateHandler) {
|
||||||
this.tenant = tenant;
|
this.ddiTenant = ddiTenant;
|
||||||
this.device = device;
|
this.mgmtApi = mgmtApi;
|
||||||
this.hawkbitClient = hawkbitClient;
|
String controllerId = System.getProperty("demo.controller.id");
|
||||||
|
String securityToken = System.getProperty("demo.controller.securityToken");
|
||||||
|
|
||||||
|
this.device = this.ddiTenant.createController(Controller.builder()
|
||||||
|
.controllerId(controllerId)
|
||||||
|
.securityToken(ObjectUtils.isEmpty(securityToken) ?
|
||||||
|
(ObjectUtils.isEmpty(ddiTenant.getTenant().getGatewayToken()) ? MgmtApi.randomToken() : securityToken) :
|
||||||
|
securityToken)
|
||||||
|
.build(),
|
||||||
|
updateHandler.orElse(null)).setOverridePollMillis(10_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "setup")
|
@ShellMethod(key = "setup")
|
||||||
public void setup() {
|
public void setup() {
|
||||||
SetupHelper.setupTargetAuthentication(hawkbitClient, tenant);
|
mgmtApi.setupTargetAuthentication();
|
||||||
SetupHelper.setupTargetToken(
|
mgmtApi.setupTargetToken(device.getControllerId(),device.getTargetSecurityToken());
|
||||||
device.getControllerId(), device.getTargetSecurityToken(), hawkbitClient, tenant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "start")
|
@ShellMethod(key = "start")
|
||||||
public void start() {
|
public void start() {
|
||||||
device.start(scheduler);
|
device.start(Executors.newSingleThreadScheduledExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "stop")
|
@ShellMethod(key = "stop")
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.springframework.shell.standard.ShellMethod;
|
|||||||
import org.springframework.shell.standard.ShellOption;
|
import org.springframework.shell.standard.ShellOption;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class representing DDI device connecting directly to hawkVit.
|
* Abstract class representing DDI device connecting directly to hawkVit.
|
||||||
@@ -45,33 +46,35 @@ public class DmfApp {
|
|||||||
return new Amqp(rabbitProperties, amqpProperties);
|
return new Amqp(rabbitProperties, amqpProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
DmfTenant dmfTenant(Tenant tenant, Amqp amqp) {
|
||||||
|
return new DmfTenant(tenant, amqp);
|
||||||
|
}
|
||||||
|
|
||||||
@ShellComponent
|
@ShellComponent
|
||||||
public static class Shell {
|
public static class Shell {
|
||||||
|
|
||||||
private final UpdateHandler updateHandler;
|
|
||||||
private final DmfTenant dmfTenant;
|
private final DmfTenant dmfTenant;
|
||||||
|
private final UpdateHandler updateHandler;
|
||||||
|
|
||||||
Shell(final Tenant tenant, final Optional<UpdateHandler> updateHandler, final Amqp amqp) {
|
Shell(final DmfTenant dmfTenant, final Optional<UpdateHandler> updateHandler) {
|
||||||
|
this.dmfTenant = dmfTenant;
|
||||||
this.updateHandler = updateHandler.orElse(null);
|
this.updateHandler = updateHandler.orElse(null);
|
||||||
dmfTenant = new DmfTenant(tenant, amqp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "start-one")
|
@ShellMethod(key = "start-one")
|
||||||
public void startOne(@ShellOption("--id") final String controllerId) {
|
public void startOne(@ShellOption("--id") final String controllerId) {
|
||||||
if (dmfTenant.getController(controllerId).isEmpty()) {
|
dmfTenant.getController(controllerId).ifPresentOrElse(
|
||||||
dmfTenant.create(
|
dmfController -> dmfController.start(Executors.newSingleThreadScheduledExecutor()),
|
||||||
Controller.builder().controllerId(controllerId).build(),
|
() -> dmfTenant.createController(Controller.builder().controllerId(controllerId).build(), updateHandler)
|
||||||
updateHandler).connect();
|
.start(Executors.newSingleThreadScheduledExecutor()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "stop-one")
|
@ShellMethod(key = "stop-one")
|
||||||
public void stopOne(@ShellOption("--id") final String controllerId) {
|
public void stopOne(@ShellOption("--id") final String controllerId) {
|
||||||
dmfTenant.getController(controllerId).ifPresentOrElse(
|
dmfTenant.getController(controllerId).ifPresentOrElse(
|
||||||
DmfController::stop,
|
DmfController::stop,
|
||||||
() -> {
|
() -> log.error("Controller with id " + controllerId + " not found!"));
|
||||||
throw new IllegalArgumentException("Controller with id " + controllerId + " not found!");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "start")
|
@ShellMethod(key = "start")
|
||||||
|
|||||||
@@ -15,26 +15,22 @@ import feign.codec.Decoder;
|
|||||||
import feign.codec.Encoder;
|
import feign.codec.Encoder;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.sdk.Controller;
|
import org.eclipse.hawkbit.sdk.Controller;
|
||||||
import org.eclipse.hawkbit.sdk.HawkbitServer;
|
|
||||||
import org.eclipse.hawkbit.sdk.HawkbitClient;
|
import org.eclipse.hawkbit.sdk.HawkbitClient;
|
||||||
import org.eclipse.hawkbit.sdk.HawkbitSDKConfigurtion;
|
import org.eclipse.hawkbit.sdk.HawkbitServer;
|
||||||
import org.eclipse.hawkbit.sdk.Tenant;
|
import org.eclipse.hawkbit.sdk.Tenant;
|
||||||
import org.eclipse.hawkbit.sdk.demo.SetupHelper;
|
|
||||||
import org.eclipse.hawkbit.sdk.device.DdiController;
|
import org.eclipse.hawkbit.sdk.device.DdiController;
|
||||||
|
import org.eclipse.hawkbit.sdk.device.DdiTenant;
|
||||||
import org.eclipse.hawkbit.sdk.device.UpdateHandler;
|
import org.eclipse.hawkbit.sdk.device.UpdateHandler;
|
||||||
|
import org.eclipse.hawkbit.sdk.mgmt.MgmtApi;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.shell.standard.ShellComponent;
|
import org.springframework.shell.standard.ShellComponent;
|
||||||
import org.springframework.shell.standard.ShellMethod;
|
import org.springframework.shell.standard.ShellMethod;
|
||||||
import org.springframework.shell.standard.ShellOption;
|
import org.springframework.shell.standard.ShellOption;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class representing DDI device connecting directly to hawkVit.
|
* Abstract class representing DDI device connecting directly to hawkVit.
|
||||||
@@ -54,66 +50,66 @@ public class MultiDeviceApp {
|
|||||||
return new HawkbitClient(hawkBitServer, client, encoder, decoder, contract);
|
return new HawkbitClient(hawkBitServer, client, encoder, decoder, contract);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
DdiTenant ddiTenant(final Tenant defaultTenant,
|
||||||
|
final HawkbitClient hawkbitClient) {
|
||||||
|
return new DdiTenant(defaultTenant, hawkbitClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MgmtApi mgmtApi(final Tenant defaultTenant, final HawkbitClient hawkbitClient) {
|
||||||
|
return new MgmtApi(defaultTenant, hawkbitClient);
|
||||||
|
}
|
||||||
|
|
||||||
@ShellComponent
|
@ShellComponent
|
||||||
public static class Shell {
|
public static class Shell {
|
||||||
|
|
||||||
private final Tenant tenant;
|
private final DdiTenant ddiTenant;
|
||||||
|
private final MgmtApi mgmtApi;
|
||||||
private final UpdateHandler updateHandler;
|
private final UpdateHandler updateHandler;
|
||||||
private final HawkbitClient hawkbitClient;
|
|
||||||
private final Map<String, DdiController> devices = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
|
|
||||||
private boolean setup;
|
private boolean setup;
|
||||||
|
|
||||||
Shell(final Tenant tenant, final Optional<UpdateHandler> updateHandler, final HawkbitClient hawkbitClient) {
|
Shell(final DdiTenant ddiTenant, final MgmtApi mgmtApi, final Optional<UpdateHandler> updateHandler) {
|
||||||
this.tenant = tenant;
|
this.ddiTenant = ddiTenant;
|
||||||
|
this.mgmtApi = mgmtApi;
|
||||||
this.updateHandler = updateHandler.orElse(null);
|
this.updateHandler = updateHandler.orElse(null);
|
||||||
this.hawkbitClient = hawkbitClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "setup")
|
@ShellMethod(key = "setup")
|
||||||
public void setup() {
|
public void setup() {
|
||||||
SetupHelper.setupTargetAuthentication(hawkbitClient, tenant);
|
mgmtApi.setupTargetAuthentication();
|
||||||
setup = true;
|
setup = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "start-one")
|
@ShellMethod(key = "start-one")
|
||||||
public void startOne(@ShellOption("--id") final String controllerId) {
|
public void startOne(@ShellOption("--id") final String controllerId) {
|
||||||
DdiController device = devices.get(controllerId);
|
|
||||||
final String securityTargetToken;
|
final String securityTargetToken;
|
||||||
if (setup) {
|
if (setup) {
|
||||||
securityTargetToken = SetupHelper.setupTargetToken(
|
securityTargetToken = mgmtApi.setupTargetToken(controllerId,null);
|
||||||
controllerId, null, hawkbitClient, tenant);
|
|
||||||
} else {
|
} else {
|
||||||
securityTargetToken = null;
|
securityTargetToken = null;
|
||||||
}
|
}
|
||||||
if (device == null) {
|
// Create device with security token if not yet registered in this execution
|
||||||
device = new DdiController(
|
// if already created in this execution of app, just start the poll
|
||||||
tenant,
|
// for each new device - separate ThreadScheduler
|
||||||
Controller.builder()
|
ddiTenant.getController(controllerId).ifPresentOrElse(
|
||||||
|
ddiController -> ddiController.start(Executors.newSingleThreadScheduledExecutor()),
|
||||||
|
() -> ddiTenant.createController(Controller.builder()
|
||||||
.controllerId(controllerId)
|
.controllerId(controllerId)
|
||||||
.securityToken(securityTargetToken)
|
.securityToken(securityTargetToken)
|
||||||
.build(),
|
.build(),updateHandler)
|
||||||
updateHandler,
|
.setOverridePollMillis(10_000)
|
||||||
hawkbitClient).setOverridePollMillis(10_000);
|
.start(Executors.newSingleThreadScheduledExecutor())
|
||||||
final DdiController oldDevice = devices.putIfAbsent(controllerId, device);
|
);
|
||||||
if (oldDevice != null) {
|
|
||||||
device = oldDevice; // reuse existing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
device.start(scheduler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "stop-one")
|
@ShellMethod(key = "stop-one")
|
||||||
public void stopOne(@ShellOption("--id") final String controllerId) {
|
public void stopOne(@ShellOption("--id") final String controllerId) {
|
||||||
final DdiController device = devices.get(controllerId);
|
ddiTenant.getController(controllerId).ifPresentOrElse(
|
||||||
if (device == null) {
|
DdiController::stop,
|
||||||
throw new IllegalArgumentException("Controller with id " + controllerId + " not found!");
|
() -> log.error("Controller with id " + controllerId + " not found!"));
|
||||||
} else {
|
|
||||||
device.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = "start")
|
@ShellMethod(key = "start")
|
||||||
|
|||||||
@@ -35,5 +35,6 @@
|
|||||||
<artifactId>hawkbit-ddi-api</artifactId>
|
<artifactId>hawkbit-ddi-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -9,17 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.sdk.device;
|
package org.eclipse.hawkbit.sdk.device;
|
||||||
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.temporal.ChronoField;
|
|
||||||
import java.util.AbstractMap;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
@@ -39,6 +28,17 @@ import org.springframework.hateoas.Link;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.temporal.ChronoField;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing DDI device connecting directly to hawkBit.
|
* Class representing DDI device connecting directly to hawkBit.
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +84,7 @@ public class DdiController {
|
|||||||
* for communication to hawkBit
|
* for communication to hawkBit
|
||||||
*/
|
*/
|
||||||
public DdiController(final Tenant tenant, final Controller controller,
|
public DdiController(final Tenant tenant, final Controller controller,
|
||||||
final UpdateHandler updateHandler, final HawkbitClient hawkbitClient) {
|
final UpdateHandler updateHandler, final HawkbitClient hawkbitClient) {
|
||||||
this.tenantId = tenant.getTenantId();
|
this.tenantId = tenant.getTenantId();
|
||||||
gatewayToken = tenant.getGatewayToken();
|
gatewayToken = tenant.getGatewayToken();
|
||||||
downloadAuthenticationEnabled = tenant.isDownloadAuthenticationEnabled();
|
downloadAuthenticationEnabled = tenant.isDownloadAuthenticationEnabled();
|
||||||
@@ -96,13 +96,17 @@ public class DdiController {
|
|||||||
|
|
||||||
// expects single threaded {@link java.util.concurrent.ScheduledExecutorService}
|
// expects single threaded {@link java.util.concurrent.ScheduledExecutorService}
|
||||||
public void start(final ScheduledExecutorService executorService) {
|
public void start(final ScheduledExecutorService executorService) {
|
||||||
Objects.requireNonNull(executorService, "Require non null executor!");
|
stop();
|
||||||
|
|
||||||
|
Objects.requireNonNull(executorService, "Require non null executor!");
|
||||||
this.executorService = executorService;
|
this.executorService = executorService;
|
||||||
executorService.submit(this::poll);
|
executorService.submit(this::poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
if (executorService != null) {
|
||||||
|
executorService.shutdown();
|
||||||
|
}
|
||||||
executorService = null;
|
executorService = null;
|
||||||
lastActionId = null;
|
lastActionId = null;
|
||||||
currentActionId = null;
|
currentActionId = null;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An in-memory simulated DMF Tenant to hold the controller twins in
|
* An in-memory simulated DDI Tenant to hold the controller twins in
|
||||||
* memory and be able to retrieve them again.
|
* memory and be able to retrieve them again.
|
||||||
*/
|
*/
|
||||||
public class DdiTenant {
|
public class DdiTenant {
|
||||||
@@ -27,8 +27,9 @@ public class DdiTenant {
|
|||||||
@Getter
|
@Getter
|
||||||
private final Tenant tenant;
|
private final Tenant tenant;
|
||||||
|
|
||||||
private final Map<String, DdiController> controllers = new ConcurrentHashMap<>();
|
@Getter
|
||||||
private final HawkbitClient hawkbitClient;
|
private final HawkbitClient hawkbitClient;
|
||||||
|
private final Map<String, DdiController> controllers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public DdiTenant(final Tenant tenant, final HawkbitClient hawkbitClient) {
|
public DdiTenant(final Tenant tenant, final HawkbitClient hawkbitClient) {
|
||||||
this.tenant = tenant;
|
this.tenant = tenant;
|
||||||
@@ -40,17 +41,14 @@ public class DdiTenant {
|
|||||||
controllers.clear();
|
controllers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DdiController create(final Controller controller, final UpdateHandler updateHandler) {
|
public DdiController createController(final Controller controller, final UpdateHandler updateHandler) {
|
||||||
final DdiController ddiController = new DdiController(tenant, controller, updateHandler, hawkbitClient);
|
final DdiController ddiController = new DdiController(tenant, controller, updateHandler, hawkbitClient);
|
||||||
controllers.put(controller.getControllerId(), ddiController);
|
controllers.put(controller.getControllerId(), ddiController);
|
||||||
return ddiController;
|
return ddiController;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(final String controllerId) {
|
|
||||||
Optional.ofNullable(controllers.remove(controllerId)).ifPresent(DdiController::stop);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<DdiController> getController(final String controllerId) {
|
public Optional<DdiController> getController(final String controllerId) {
|
||||||
return Optional.ofNullable(controllers.get(controllerId));
|
return Optional.ofNullable(controllers.get(controllerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ import org.eclipse.hawkbit.sdk.dmf.amqp.DmfSender;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing DMF device twin connecting to hawkBit via DMF.
|
* Class representing DMF device twin connecting to hawkBit via DMF.
|
||||||
@@ -50,6 +51,9 @@ public class DmfController {
|
|||||||
|
|
||||||
private volatile Long lastActionId;
|
private volatile Long lastActionId;
|
||||||
|
|
||||||
|
@SuppressWarnings("java:S3077") // volatile used only for the reference as expected
|
||||||
|
private volatile ScheduledExecutorService executorService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new device instance.
|
* Creates a new device instance.
|
||||||
*
|
*
|
||||||
@@ -67,26 +71,32 @@ public class DmfController {
|
|||||||
this.dmfSender = dmfSender;
|
this.dmfSender = dmfSender;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect() {
|
public void start(ScheduledExecutorService executorService) {
|
||||||
|
stop();
|
||||||
|
this.executorService = executorService;
|
||||||
log.debug(LOG_PREFIX + "Connecting/Polling ...", getTenantId(), getControllerId());
|
log.debug(LOG_PREFIX + "Connecting/Polling ...", getTenantId(), getControllerId());
|
||||||
dmfSender.createOrUpdateThing(getTenantId(), getControllerId());
|
dmfSender.createOrUpdateThing(getTenantId(), getControllerId());
|
||||||
log.debug(LOG_PREFIX + "Done. Create thing sent.", getTenantId(), getControllerId());
|
log.debug(LOG_PREFIX + "Done. Create thing sent.", getTenantId(), getControllerId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void poll() {
|
public void unregisterThing() {
|
||||||
log.debug(LOG_PREFIX + "Polling ..", getTenantId(), getControllerId());
|
log.debug(LOG_PREFIX + "Removing Controller...", getTenantId(), getControllerId());
|
||||||
dmfSender.createOrUpdateThing(getTenantId(), getControllerId());
|
dmfSender.removeThing(getTenantId(), getControllerId());
|
||||||
log.debug(LOG_PREFIX + "Done. Create thing sent.", getTenantId(), getControllerId());
|
log.debug(LOG_PREFIX + "Done. Create thing sent.", getTenantId(), getControllerId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
if (executorService != null) {
|
||||||
|
executorService.shutdown();
|
||||||
|
}
|
||||||
|
executorService = null;
|
||||||
lastActionId = null;
|
lastActionId = null;
|
||||||
currentActionId = null;
|
currentActionId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processUpdate(final EventTopic actionType, final DmfDownloadAndUpdateRequest updateRequest) {
|
public void processUpdate(final EventTopic actionType, final DmfDownloadAndUpdateRequest updateRequest) {
|
||||||
log.info(LOG_PREFIX + "Processing update for action {} .", getTenantId(), controllerId, updateRequest.getActionId());
|
log.info(LOG_PREFIX + "Processing update for action {} .", getTenantId(), controllerId, updateRequest.getActionId());
|
||||||
updateHandler.getUpdateProcessor(this, actionType, updateRequest).run();
|
executorService.submit(updateHandler.getUpdateProcessor(this, actionType, updateRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendFeedback(final UpdateStatus updateStatus) {
|
public void sendFeedback(final UpdateStatus updateStatus) {
|
||||||
|
|||||||
@@ -46,17 +46,21 @@ public class DmfTenant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
controllers.values().forEach(DmfController::stop);
|
controllers.values().forEach(DmfController::unregisterThing);
|
||||||
controllers.clear();
|
controllers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DmfController create(final Controller controller, final UpdateHandler updateHandler) {
|
public DmfController createController(final Controller controller, final UpdateHandler updateHandler) {
|
||||||
final DmfController dmfController = new DmfController(tenant, controller, updateHandler, vHost);
|
final DmfController dmfController = new DmfController(tenant, controller, updateHandler, vHost);
|
||||||
controllers.put(controller.getControllerId(), dmfController);
|
controllers.put(controller.getControllerId(), dmfController);
|
||||||
return dmfController;
|
return dmfController;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(final String controllerId) {
|
public void removeController(final String controllerId) {
|
||||||
|
Optional.ofNullable(controllers.remove(controllerId)).ifPresent(DmfController::unregisterThing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleThingDeleted(final String controllerId) {
|
||||||
Optional.ofNullable(controllers.remove(controllerId)).ifPresent(DmfController::stop);
|
Optional.ofNullable(controllers.remove(controllerId)).ifPresent(DmfController::stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,16 @@ public class DmfSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void createOrUpdateThing(final String tenant, final String controllerId) {
|
public void createOrUpdateThing(final String tenant, final String controllerId) {
|
||||||
|
sendThingMessage(tenant, controllerId, MessageType.THING_CREATED.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeThing(final String tenant, final String controllerId) {
|
||||||
|
sendThingMessage(tenant, controllerId, MessageType.THING_REMOVED.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendThingMessage(final String tenant, final String controllerId, String thingStatusChange) {
|
||||||
final MessageProperties messagePropertiesForSP = new MessageProperties();
|
final MessageProperties messagePropertiesForSP = new MessageProperties();
|
||||||
messagePropertiesForSP.setHeader(MessageHeaderKey.TYPE, MessageType.THING_CREATED.name());
|
messagePropertiesForSP.setHeader(MessageHeaderKey.TYPE, thingStatusChange);
|
||||||
messagePropertiesForSP.setHeader(MessageHeaderKey.TENANT, tenant);
|
messagePropertiesForSP.setHeader(MessageHeaderKey.TENANT, tenant);
|
||||||
messagePropertiesForSP.setHeader(MessageHeaderKey.THING_ID, controllerId);
|
messagePropertiesForSP.setHeader(MessageHeaderKey.THING_ID, controllerId);
|
||||||
messagePropertiesForSP.setHeader(MessageHeaderKey.SENDER, "hawkBit-sdk");
|
messagePropertiesForSP.setHeader(MessageHeaderKey.SENDER, "hawkBit-sdk");
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public class VHost extends DmfSender implements MessageListener {
|
|||||||
final String controllerId = (String)message.getMessageProperties().getHeaders().get(MessageHeaderKey.THING_ID);
|
final String controllerId = (String)message.getMessageProperties().getHeaders().get(MessageHeaderKey.THING_ID);
|
||||||
final String type = (String)message.getMessageProperties().getHeaders().get(MessageHeaderKey.TYPE);
|
final String type = (String)message.getMessageProperties().getHeaders().get(MessageHeaderKey.TYPE);
|
||||||
|
|
||||||
log.info("Message received for target {}, value : {}", controllerId, message.toString());
|
log.info("Message received for target {}, value : {}", controllerId, message);
|
||||||
switch (MessageType.valueOf(type)) {
|
switch (MessageType.valueOf(type)) {
|
||||||
case EVENT: {
|
case EVENT: {
|
||||||
checkContentTypeJson(message);
|
checkContentTypeJson(message);
|
||||||
@@ -112,7 +112,7 @@ public class VHost extends DmfSender implements MessageListener {
|
|||||||
}
|
}
|
||||||
case THING_DELETED: {
|
case THING_DELETED: {
|
||||||
checkContentTypeJson(message);
|
checkContentTypeJson(message);
|
||||||
Optional.ofNullable(dmfTenants.get(tenantId)).ifPresent(dmfTenant -> dmfTenant.remove(controllerId));
|
Optional.ofNullable(dmfTenants.get(tenantId)).ifPresent(dmfTenant -> dmfTenant.handleThingDeleted(controllerId));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PING_RESPONSE: {
|
case PING_RESPONSE: {
|
||||||
@@ -237,7 +237,7 @@ public class VHost extends DmfSender implements MessageListener {
|
|||||||
final String tenant = getTenant(message);
|
final String tenant = getTenant(message);
|
||||||
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message,
|
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message,
|
||||||
DmfDownloadAndUpdateRequest.class);
|
DmfDownloadAndUpdateRequest.class);
|
||||||
dmfTenants.get(tenant).getController(controllerId).get().setCurrentActionId(downloadAndUpdateRequest.getActionId());
|
dmfTenants.get(tenant).getController(controllerId).ifPresent(controller -> controller.setCurrentActionId(downloadAndUpdateRequest.getActionId()));
|
||||||
processUpdate(tenant, controllerId, actionType, downloadAndUpdateRequest);
|
processUpdate(tenant, controllerId, actionType, downloadAndUpdateRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
hawkbit-sdk/hawkbit-sdk-mgmt/pom.xml
Normal file
51
hawkbit-sdk/hawkbit-sdk-mgmt/pom.xml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2023 Bosch.IO GmbH and others
|
||||||
|
|
||||||
|
This program and the accompanying materials are made
|
||||||
|
available under the terms of the Eclipse Public License 2.0
|
||||||
|
which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
|
||||||
|
SPDX-License-Identifier: EPL-2.0
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-sdk</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>hawkbit-sdk-mgmt</artifactId>
|
||||||
|
|
||||||
|
<name>hawkBit :: SDK :: Management Api SDK</name>
|
||||||
|
<description>Management Api SDK</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-sdk-commons</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-mgmt-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
<version>${spring-cloud-starter-openfeign.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.openfeign</groupId>
|
||||||
|
<artifactId>feign-hc5</artifactId>
|
||||||
|
<version>${openfeign-hc5.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -7,11 +7,12 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.sdk.demo;
|
package org.eclipse.hawkbit.sdk.mgmt;
|
||||||
|
|
||||||
|
|
||||||
import feign.FeignException;
|
import feign.FeignException;
|
||||||
import lombok.AccessLevel;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NonNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
|
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
|
||||||
@@ -29,21 +30,28 @@ import java.util.Objects;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class representing DDI device connecting directly to hawkVit.
|
* Management Api Interface
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SetupHelper {
|
@AllArgsConstructor
|
||||||
|
public class MgmtApi {
|
||||||
|
|
||||||
private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY = "authentication.gatewaytoken.key";
|
private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY = "authentication.gatewaytoken.key";
|
||||||
private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED = "authentication.gatewaytoken.enabled";
|
private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED = "authentication.gatewaytoken.enabled";
|
||||||
private static final String AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED = "authentication.targettoken.enabled";
|
private static final String AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED = "authentication.targettoken.enabled";
|
||||||
|
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Tenant tenant;
|
||||||
|
@NonNull
|
||||||
|
private final HawkbitClient hawkbitClient;
|
||||||
|
|
||||||
|
|
||||||
// if gateway toke is configured then the gateway auth is enabled key is set
|
// if gateway toke is configured then the gateway auth is enabled key is set
|
||||||
// so all devices use gateway token authentication
|
// so all devices use gateway token authentication
|
||||||
// otherwise target token authentication is enabled. Then all devices shall be registerd
|
// otherwise target token authentication is enabled. Then all devices shall be registerd
|
||||||
// and the target token shall be set to the one from the DDI controller instance
|
// and the target token shall be set to the one from the DDI controller instance
|
||||||
public static void setupTargetAuthentication(final HawkbitClient hawkbitClient, final Tenant tenant) {
|
public void setupTargetAuthentication() {
|
||||||
final MgmtTenantManagementRestApi mgmtTenantManagementRestApi =
|
final MgmtTenantManagementRestApi mgmtTenantManagementRestApi =
|
||||||
hawkbitClient.mgmtService(MgmtTenantManagementRestApi.class, tenant);
|
hawkbitClient.mgmtService(MgmtTenantManagementRestApi.class, tenant);
|
||||||
final String gatewayToken = tenant.getGatewayToken();
|
final String gatewayToken = tenant.getGatewayToken();
|
||||||
@@ -75,9 +83,7 @@ public class SetupHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns target token
|
// returns target token
|
||||||
public static String setupTargetToken(
|
public String setupTargetToken(final String controllerId, String securityTargetToken) {
|
||||||
final String controllerId, String securityTargetToken,
|
|
||||||
final HawkbitClient hawkbitClient, final Tenant tenant) {
|
|
||||||
if (ObjectUtils.isEmpty(tenant.getGatewayToken())) {
|
if (ObjectUtils.isEmpty(tenant.getGatewayToken())) {
|
||||||
final MgmtTargetRestApi mgmtTargetRestApi = hawkbitClient.mgmtService(MgmtTargetRestApi.class, tenant);
|
final MgmtTargetRestApi mgmtTargetRestApi = hawkbitClient.mgmtService(MgmtTargetRestApi.class, tenant);
|
||||||
try {
|
try {
|
||||||
@@ -112,6 +118,10 @@ public class SetupHelper {
|
|||||||
return securityTargetToken;
|
return securityTargetToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteController(final String controllerId) {
|
||||||
|
hawkbitClient.mgmtService(MgmtTargetRestApi.class, tenant).deleteTarget(controllerId);
|
||||||
|
}
|
||||||
|
|
||||||
private static final Random RND = new SecureRandom();
|
private static final Random RND = new SecureRandom();
|
||||||
public static String randomToken() {
|
public static String randomToken() {
|
||||||
final byte[] rnd = new byte[24];
|
final byte[] rnd = new byte[24];
|
||||||
@@ -22,8 +22,14 @@
|
|||||||
<artifactId>hawkbit-sdk</artifactId>
|
<artifactId>hawkbit-sdk</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<spring-cloud-starter-openfeign.version>4.1.0</spring-cloud-starter-openfeign.version>
|
||||||
|
<openfeign-hc5.version>13.2.1</openfeign-hc5.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>hawkbit-sdk-commons</module>
|
<module>hawkbit-sdk-commons</module>
|
||||||
|
<module>hawkbit-sdk-mgmt</module>
|
||||||
<module>hawkbit-sdk-device</module>
|
<module>hawkbit-sdk-device</module>
|
||||||
<module>hawkbit-sdk-dmf</module>
|
<module>hawkbit-sdk-dmf</module>
|
||||||
<module>hawkbit-sdk-demo</module>
|
<module>hawkbit-sdk-demo</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user