Skip to content

Commit

Permalink
Propose SDK Refactor (#1821)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
vasilchev authored Aug 19, 2024
1 parent d958d8e commit ac34b95
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 131 deletions.
6 changes: 1 addition & 5 deletions hawkbit-sdk/hawkbit-sdk-commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
<name>hawkBit :: SDK :: Commons</name>
<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>
<dependency>
Expand All @@ -39,7 +36,6 @@
<artifactId>feign-hc5</artifactId>
<version>${openfeign-hc5.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion hawkbit-sdk/hawkbit-sdk-demo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-mgmt-api</artifactId>
<artifactId>hawkbit-sdk-mgmt</artifactId>
<version>${project.version}</version>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,22 @@
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.sdk.Controller;
import org.eclipse.hawkbit.sdk.HawkbitServer;
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.demo.SetupHelper;
import org.eclipse.hawkbit.sdk.device.DdiController;
import org.eclipse.hawkbit.sdk.device.DdiTenant;
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.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import org.springframework.util.ObjectUtils;

import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
* Abstract class representing DDI device connecting directly to hawkVit.
Expand All @@ -54,49 +51,49 @@ HawkbitClient hawkbitClient(
}

@Bean
DdiController device(
@Value("${hawkbit.device:controller-default}") final String controllerId,
@Value("${hawkbit.device.securityToken:}") final String securityToken,
final Tenant defaultTenant,
final Optional<UpdateHandler> updateHandler,
final HawkbitClient hawkbitClient) {
return new DdiController(
defaultTenant,
Controller.builder()
.controllerId(controllerId)
.securityToken(ObjectUtils.isEmpty(securityToken) ?
(ObjectUtils.isEmpty(defaultTenant.getGatewayToken()) ? SetupHelper.randomToken() : securityToken) :
securityToken)
.build(),
updateHandler.orElse(null),
hawkbitClient).setOverridePollMillis(10_000);
DdiTenant ddiTenant(final Tenant defaultTenant,
final HawkbitClient hawkbitClient) {
return new DdiTenant(defaultTenant, hawkbitClient);
}

@Bean
MgmtApi mgmtApi(final Tenant tenant, final HawkbitClient hawkbitClient) {
return new MgmtApi(tenant, hawkbitClient);
}

@ShellComponent
public static class Shell {

private final Tenant tenant;
private final DdiTenant ddiTenant;

private final DdiController device;
private final HawkbitClient hawkbitClient;
private final MgmtApi mgmtApi;


private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
Shell(final DdiTenant ddiTenant, final MgmtApi mgmtApi, final Optional<UpdateHandler> updateHandler) {
this.ddiTenant = ddiTenant;
this.mgmtApi = mgmtApi;
String controllerId = System.getProperty("demo.controller.id");
String securityToken = System.getProperty("demo.controller.securityToken");

Shell(final Tenant tenant, final DdiController device, final HawkbitClient hawkbitClient) {
this.tenant = tenant;
this.device = device;
this.hawkbitClient = hawkbitClient;
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")
public void setup() {
SetupHelper.setupTargetAuthentication(hawkbitClient, tenant);
SetupHelper.setupTargetToken(
device.getControllerId(), device.getTargetSecurityToken(), hawkbitClient, tenant);
mgmtApi.setupTargetAuthentication();
mgmtApi.setupTargetToken(device.getControllerId(),device.getTargetSecurityToken());
}

@ShellMethod(key = "start")
public void start() {
device.start(scheduler);
device.start(Executors.newSingleThreadScheduledExecutor());
}

@ShellMethod(key = "stop")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.springframework.shell.standard.ShellOption;

import java.util.Optional;
import java.util.concurrent.Executors;

/**
* Abstract class representing DDI device connecting directly to hawkVit.
Expand All @@ -45,33 +46,35 @@ Amqp amqp(final RabbitProperties rabbitProperties, final AmqpProperties amqpProp
return new Amqp(rabbitProperties, amqpProperties);
}

@Bean
DmfTenant dmfTenant(Tenant tenant, Amqp amqp) {
return new DmfTenant(tenant, amqp);
}

@ShellComponent
public static class Shell {

private final UpdateHandler updateHandler;
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);
dmfTenant = new DmfTenant(tenant, amqp);
}

@ShellMethod(key = "start-one")
public void startOne(@ShellOption("--id") final String controllerId) {
if (dmfTenant.getController(controllerId).isEmpty()) {
dmfTenant.create(
Controller.builder().controllerId(controllerId).build(),
updateHandler).connect();
}
dmfTenant.getController(controllerId).ifPresentOrElse(
dmfController -> dmfController.start(Executors.newSingleThreadScheduledExecutor()),
() -> dmfTenant.createController(Controller.builder().controllerId(controllerId).build(), updateHandler)
.start(Executors.newSingleThreadScheduledExecutor()));
}

@ShellMethod(key = "stop-one")
public void stopOne(@ShellOption("--id") final String controllerId) {
dmfTenant.getController(controllerId).ifPresentOrElse(
DmfController::stop,
() -> {
throw new IllegalArgumentException("Controller with id " + controllerId + " not found!");
});
() -> log.error("Controller with id " + controllerId + " not found!"));
}

@ShellMethod(key = "start")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,22 @@
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.sdk.Controller;
import org.eclipse.hawkbit.sdk.HawkbitServer;
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.demo.SetupHelper;
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.mgmt.MgmtApi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import org.springframework.shell.standard.ShellOption;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
* Abstract class representing DDI device connecting directly to hawkVit.
Expand All @@ -54,66 +50,66 @@ HawkbitClient hawkbitClient(
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
public static class Shell {

private final Tenant tenant;
private final DdiTenant ddiTenant;
private final MgmtApi mgmtApi;
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;

Shell(final Tenant tenant, final Optional<UpdateHandler> updateHandler, final HawkbitClient hawkbitClient) {
this.tenant = tenant;
Shell(final DdiTenant ddiTenant, final MgmtApi mgmtApi, final Optional<UpdateHandler> updateHandler) {
this.ddiTenant = ddiTenant;
this.mgmtApi = mgmtApi;
this.updateHandler = updateHandler.orElse(null);
this.hawkbitClient = hawkbitClient;
}

@ShellMethod(key = "setup")
public void setup() {
SetupHelper.setupTargetAuthentication(hawkbitClient, tenant);
mgmtApi.setupTargetAuthentication();
setup = true;
}

@ShellMethod(key = "start-one")
public void startOne(@ShellOption("--id") final String controllerId) {
DdiController device = devices.get(controllerId);
final String securityTargetToken;
if (setup) {
securityTargetToken = SetupHelper.setupTargetToken(
controllerId, null, hawkbitClient, tenant);
securityTargetToken = mgmtApi.setupTargetToken(controllerId,null);
} else {
securityTargetToken = null;
}
if (device == null) {
device = new DdiController(
tenant,
Controller.builder()
// Create device with security token if not yet registered in this execution
// if already created in this execution of app, just start the poll
// for each new device - separate ThreadScheduler
ddiTenant.getController(controllerId).ifPresentOrElse(
ddiController -> ddiController.start(Executors.newSingleThreadScheduledExecutor()),
() -> ddiTenant.createController(Controller.builder()
.controllerId(controllerId)
.securityToken(securityTargetToken)
.build(),
updateHandler,
hawkbitClient).setOverridePollMillis(10_000);
final DdiController oldDevice = devices.putIfAbsent(controllerId, device);
if (oldDevice != null) {
device = oldDevice; // reuse existing
}
}

device.start(scheduler);
.build(),updateHandler)
.setOverridePollMillis(10_000)
.start(Executors.newSingleThreadScheduledExecutor())
);
}

@ShellMethod(key = "stop-one")
public void stopOne(@ShellOption("--id") final String controllerId) {
final DdiController device = devices.get(controllerId);
if (device == null) {
throw new IllegalArgumentException("Controller with id " + controllerId + " not found!");
} else {
device.stop();
}
ddiTenant.getController(controllerId).ifPresentOrElse(
DdiController::stop,
() -> log.error("Controller with id " + controllerId + " not found!"));

}

@ShellMethod(key = "start")
Expand Down
1 change: 1 addition & 0 deletions hawkbit-sdk/hawkbit-sdk-device/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
<artifactId>hawkbit-ddi-api</artifactId>
<version>${project.version}</version>
</dependency>

</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,6 @@
*/
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.Setter;
import lombok.experimental.Accessors;
Expand All @@ -39,6 +28,17 @@
import org.springframework.http.HttpStatus;
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.
*/
Expand Down Expand Up @@ -84,7 +84,7 @@ public class DdiController {
* for communication to hawkBit
*/
public DdiController(final Tenant tenant, final Controller controller,
final UpdateHandler updateHandler, final HawkbitClient hawkbitClient) {
final UpdateHandler updateHandler, final HawkbitClient hawkbitClient) {
this.tenantId = tenant.getTenantId();
gatewayToken = tenant.getGatewayToken();
downloadAuthenticationEnabled = tenant.isDownloadAuthenticationEnabled();
Expand All @@ -96,13 +96,17 @@ public DdiController(final Tenant tenant, final Controller controller,

// expects single threaded {@link java.util.concurrent.ScheduledExecutorService}
public void start(final ScheduledExecutorService executorService) {
Objects.requireNonNull(executorService, "Require non null executor!");
stop();

Objects.requireNonNull(executorService, "Require non null executor!");
this.executorService = executorService;
executorService.submit(this::poll);
}

public void stop() {
if (executorService != null) {
executorService.shutdown();
}
executorService = null;
lastActionId = null;
currentActionId = null;
Expand Down
Loading

0 comments on commit ac34b95

Please sign in to comment.