-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce inital draft of hawkBit SDK (#1638)
Intends to provide a Java SDK facilitating: * development of back-end integrations using mgmt api (including UI-s) * development of java based high-end devices (which could run Spring apps) to communicate with hawkBit via DDI API * implementation of demo/test cases using device & management SDK Status: initial draft - Feign client did & management API - done - Hal/HATEAOS Support - works (including in non-web apps) - device communication works when no software updates (e.g. pulling software base) - demo for single and multiple devices simulation (including management API uses) - TODO - fix software update flows - TODO - provide more integration points for developers to interact with device SDK Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
- Loading branch information
1 parent
0a01a23
commit 3b6570b
Showing
20 changed files
with
1,410 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,6 +61,7 @@ maven.properties | |
|
||
# Test Files | ||
*.tmp | ||
spring-shell.log | ||
|
||
# Documentation | ||
.gitmodules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<!-- | ||
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-commons</artifactId> | ||
<name>hawkBit :: SDK :: Commons</name> | ||
<description>SDK commons</description> | ||
|
||
<properties> | ||
<spring-cloud-starter-openfeign.version>4.0.4</spring-cloud-starter-openfeign.version> | ||
<openfeign-hc5.version>13.0</openfeign-hc5.version> | ||
</properties> | ||
|
||
<dependencies> | ||
<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> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-hateoas</artifactId> | ||
</dependency> | ||
</dependencies> | ||
</project> |
29 changes: 29 additions & 0 deletions
29
hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/Controller.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/** | ||
* 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 | ||
*/ | ||
package org.eclipse.hawkbit.sdk; | ||
|
||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.ToString; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.lang.NonNull; | ||
import org.springframework.lang.Nullable; | ||
|
||
@Data | ||
@Builder | ||
public class Controller { | ||
|
||
// id of the tenant | ||
@NonNull | ||
private String controllerId; | ||
// (target) security token | ||
@Nullable | ||
private String securityToken; | ||
} |
94 changes: 94 additions & 0 deletions
94
hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
* Copyright (c) 2023 Contributors to the Eclipse Foundation | ||
* | ||
* 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 | ||
*/ | ||
package org.eclipse.hawkbit.sdk; | ||
|
||
import feign.Client; | ||
import feign.Contract; | ||
import feign.Feign; | ||
import feign.codec.Decoder; | ||
import feign.codec.Encoder; | ||
import feign.codec.ErrorDecoder; | ||
import lombok.Builder; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.util.ObjectUtils; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.util.Base64; | ||
import java.util.Objects; | ||
|
||
@Slf4j | ||
@Builder | ||
public class HawkbitClient { | ||
|
||
private static final String AUTHORIZATION = "Authorization"; | ||
private static final ErrorDecoder DEFAULT_ERROR_DECODER = new ErrorDecoder.Default(); | ||
|
||
private final HawkbitServer hawkBitServerProperties; | ||
|
||
private final Client client; | ||
private final Encoder encoder; | ||
private final Decoder decoder; | ||
private final Contract contract; | ||
|
||
public HawkbitClient( | ||
final HawkbitServer hawkBitServerProperties, | ||
final Client client, final Encoder encoder, final Decoder decoder, final Contract contract) { | ||
this.hawkBitServerProperties = hawkBitServerProperties; | ||
this.client = client; | ||
this.encoder = encoder; | ||
this.decoder = decoder; | ||
this.contract = contract; | ||
} | ||
|
||
public <T> T mgmtService(final Class<T> serviceType, final Tenant tenantProperties) { | ||
return service(serviceType, tenantProperties, null); | ||
} | ||
public <T> T ddiService(final Class<T> serviceType, final Tenant tenantProperties, final Controller controller) { | ||
return service(serviceType, tenantProperties, controller); | ||
} | ||
|
||
private <T> T service(final Class<T> serviceType, final Tenant tenantProperties, final Controller controller) { | ||
return Feign.builder().client(client) | ||
.encoder(encoder) | ||
.decoder(decoder) | ||
.errorDecoder((methodKey, response) -> { | ||
final Exception e = DEFAULT_ERROR_DECODER.decode(methodKey, response); | ||
log.trace("REST API call failed!", e); | ||
return e; | ||
}) | ||
.contract(contract) | ||
.requestInterceptor(controller == null ? | ||
template -> { | ||
template.header(AUTHORIZATION, | ||
"Basic " + | ||
Base64.getEncoder() | ||
.encodeToString( | ||
(Objects.requireNonNull(tenantProperties.getUsername(), | ||
"User is null!") + | ||
":" + | ||
Objects.requireNonNull(tenantProperties.getPassword(), | ||
"Password is not available!")) | ||
.getBytes(StandardCharsets.ISO_8859_1))); | ||
} : | ||
template -> { | ||
if (ObjectUtils.isEmpty(tenantProperties.getGatewayToken())) { | ||
if (!ObjectUtils.isEmpty(controller.getSecurityToken())) { | ||
template.header(AUTHORIZATION, "TargetToken " + controller.getSecurityToken()); | ||
} // else do not sent authentication | ||
} else { | ||
template.header(AUTHORIZATION, "GatewayToken " + tenantProperties.getGatewayToken()); | ||
} | ||
}) | ||
.target(serviceType, | ||
controller == null ? | ||
hawkBitServerProperties.getMgmtUrl() : | ||
hawkBitServerProperties.getDdiUrl()); | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
...sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitSDKConfigurtion.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/** | ||
* 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 | ||
*/ | ||
package org.eclipse.hawkbit.sdk; | ||
|
||
import feign.Contract; | ||
import feign.MethodMetadata; | ||
import feign.RequestInterceptor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.cloud.openfeign.FeignClientsConfiguration; | ||
import org.springframework.cloud.openfeign.hateoas.WebConvertersCustomizer; | ||
import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer; | ||
import org.springframework.cloud.openfeign.support.SpringMvcContract; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.Import; | ||
import org.springframework.context.annotation.Primary; | ||
import org.springframework.hateoas.config.EnableHypermediaSupport; | ||
import org.springframework.hateoas.config.WebConverters; | ||
import org.springframework.http.MediaType; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.Method; | ||
import java.util.LinkedHashMap; | ||
|
||
@Slf4j | ||
@Configuration | ||
@EnableConfigurationProperties({ HawkbitServer.class, Tenant.class}) | ||
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL) | ||
@Import(FeignClientsConfiguration.class) | ||
public class HawkbitSDKConfigurtion { | ||
|
||
/** | ||
* An feign request interceptor to set the defined {@code Accept} and {@code Content-Type} headers for each request | ||
* to {@code application/json}. | ||
* | ||
* TODO - is this needed? | ||
*/ | ||
@Bean | ||
@Primary | ||
public RequestInterceptor jsonHeaderInterceptorOverride() { | ||
return template -> template | ||
.header("Accept", MediaType.APPLICATION_JSON_VALUE) | ||
.header("Content-Type", MediaType.APPLICATION_JSON_VALUE); | ||
} | ||
|
||
// takes place only when spring app is started in non-web-app mode | ||
// in that case org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration | ||
// is explicitly disabled and HAL/HATEOAS support doesn't work | ||
@Bean | ||
@ConditionalOnMissingBean | ||
@ConditionalOnNotWebApplication | ||
@ConditionalOnClass({ WebConverters.class}) | ||
public HttpMessageConverterCustomizer webConvertersCustomizerOverrider(WebConverters webConverters) { | ||
return new WebConvertersCustomizer(webConverters); | ||
} | ||
// another option would be something like (need to import io.github.openfeign:feign-jackson | ||
// @Bean @Primary @ConditionalOnNotWebApplication | ||
// public Decoder feignDecoderOverride() { | ||
// return new ResponseEntityDecoder(new JacksonDecoder(new ObjectMapper().registerModule(new Jackson2HalModule()))); | ||
// } | ||
|
||
/** | ||
* Own implementation of the {@link SpringMvcContract} which catches the {@link IllegalStateException} which occurs | ||
* due multiple produces and consumes values in the request-mapping | ||
* annotation.https://github.com/spring-cloud/spring-cloud-netflix/issues/808 | ||
* | ||
* TODO - is this needed? | ||
*/ | ||
@Bean | ||
@Primary | ||
public Contract feignContractOverride() { | ||
return new SpringMvcContract() { | ||
|
||
@Override | ||
protected void processAnnotationOnMethod(final MethodMetadata data, final Annotation methodAnnotation, final Method method) { | ||
try { | ||
super.processAnnotationOnMethod(data, methodAnnotation, method); | ||
} catch (final IllegalStateException e) { | ||
// ignore illegalstateexception here because it's thrown because of | ||
// multiple consumers and produces, see | ||
// https://github.com/spring-cloud/spring-cloud-netflix/issues/808 | ||
log.trace(e.getMessage(), e); | ||
|
||
// This line from super is mandatory to avoid that access to the | ||
// expander causes a nullpointer. | ||
data.indexToExpander(new LinkedHashMap<>()); | ||
} | ||
} | ||
}; | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitServer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* 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 | ||
*/ | ||
package org.eclipse.hawkbit.sdk; | ||
|
||
import lombok.Data; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.lang.NonNull; | ||
|
||
@ConfigurationProperties(prefix="hawkbit.server") | ||
@Data | ||
public class HawkbitServer { | ||
|
||
@NonNull | ||
private String mgmtUrl = "http://localhost:8080"; | ||
@NonNull | ||
private String ddiUrl = "http://localhost:8081"; | ||
} |
38 changes: 38 additions & 0 deletions
38
hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/Tenant.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* 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 | ||
*/ | ||
package org.eclipse.hawkbit.sdk; | ||
|
||
import lombok.Data; | ||
import lombok.ToString; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.lang.NonNull; | ||
import org.springframework.lang.Nullable; | ||
|
||
@ConfigurationProperties("hawkbit.tenant") | ||
@Data | ||
public class Tenant { | ||
|
||
// id of the tenant | ||
@NonNull | ||
private String tenantId = "DEFAULT"; | ||
|
||
// basic auth user, to access management api | ||
@Nullable | ||
private String username = "admin"; | ||
@ToString.Exclude | ||
@Nullable | ||
private String password = "admin"; | ||
|
||
// gateway token | ||
@Nullable | ||
private String gatewayToken; | ||
|
||
private boolean downloadAuthenticationEnabled; | ||
} |
12 changes: 12 additions & 0 deletions
12
hawkbit-sdk/hawkbit-sdk-commons/src/main/resources/application.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# | ||
# 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 | ||
# | ||
|
||
spring.cloud.openfeign.httpclient.hc5.enabled=true | ||
|
Oops, something went wrong.