Merge remote-tracking branch 'origin/master'

This commit is contained in:
Kai Zimmermann
2016-05-26 10:41:09 +02:00
612 changed files with 13976 additions and 14661 deletions

0
3rd-dependencies/listDeps.sh Executable file → Normal file
View File

View File

@@ -7,3 +7,14 @@
- hawkbit.server.email.support has changed to hawkbit.server.ui.links.support
- hawkbit.server.email.request.account has changed to hawkbit.server.ui.links.requestAccount
- hawkbit.server.im.login.url has changed to hawkbit.server.ui.links.userManagement
### REST API model changes for clients
- ENTITYPagedList classes have been removed; generic PagedList used instead (e.g. PagedList<TargetRest> instead of TargetPagedList).
- ENTITYsrest classes have been removed; List<ENTITYrest> used instead (e.g. List<TargetRest> instead of TargetsRest)
### Renamed api annotations
- Annotation `org.eclipse.hawkbit.rest.resource.EnableRestResources` have changed to `org.eclipse.hawkbit.mgmt.annotation.EnableMgmtApi`
- Annotation `org.eclipse.hawkbit.ddi.resource.EnableDirectDeviceApi` have changed to `org.eclipse.hawkbit.ddi.annotation.EnableDdiApi`
### Renamed maven modules
- Module hawkbit-mgmt-api-client have changed to hawkbit-example-mgmt-simulator

View File

@@ -14,10 +14,15 @@ see [hawkBit Wiki](https://github.com/eclipse/hawkbit/wiki)
* Having issues with hawkBit? Open a [GitHub issue](https://github.com/eclipse/hawkbit/issues).
* You can also check out our [Project Homepage](https://projects.eclipse.org/projects/iot.hawkbit) for further contact options.
# hawkBit sandbox
We offer a sandbox installation that is free for everyone to try out hawkBit. However, keep in mind that the sandbox database will be reset from time to time. It is also not possible to upload any artifacts into the sandbox. But you can use it to try out the Management UI, Management API and DDI API.
https://hawkbit.eu-gb.mybluemix.net/UI/
# Compile, Run and Getting Started
We are not providing an off the shelf installation ready hawkBit update server. However, we recommend to check out the [Example Application](examples/hawkbit-example-app) for a runtime ready Spring Boot based update server that is empowered by hawkBit.
We are not providing an off the shelf installation ready hawkBit update server. However, we recommend to check out the [Example Application](examples/hawkbit-example-app) for a runtime ready Spring Boot based update server that is empowered by hawkBit. In addition we have [guide](https://github.com/eclipse/hawkbit/wiki/Run-hawkBit) for setting up a complete landscape.
#### Clone and build hawkBit
```
@@ -36,9 +41,9 @@ $ java -jar ./examples/hawkbit-example-app/target/hawkbit-example-app-#version#.
$ java -jar ./examples/hawkbit-device-simulator/target/hawkbit-device-simulator-#version#.jar
```
#### Generate Getting Started data
[Example Management API Client](examples/hawkbit-mgmt-api-client)
[Example Management API Client](examples/hawkbit-example-mgmt-simulator)
```
$ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#version#.jar
$ java -jar ./examples/hawkbit-example-mgmt-simulator/target/hawkbit-example-mgmt-simulator-#version#.jar
```
# Releases and Roadmap
@@ -47,21 +52,27 @@ $ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#v
* The master branch contains future development towards 0.2. We are currently focusing on:
* Rollout Management for large scale rollouts.
* Clustering capabilities for the update server.
* Upgrade of Spring Boot and Vaadin depedencies.
* Upgrade of Spring Boot and Vaadin dependencies.
* And of course tons of usability improvements and bug fixes.
# Modules
`hawkbit-core` : core elements.
`hawkbit-security-core` : core security elements.
`hawkbit-security-integration` : security integration elements to integrate security into hawkbit.
`hawkbit-artifact-repository-mongo` : artifact repository implementation to mongoDB.
`hawkbit-autoconfigure` : spring-boot auto-configuration.
`hawkbit-dmf-api` : API for the Device Management Integration.
`hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API.
`hawkbit-repository` : repository implemenation based on SQL for all meta-data.
`hawkbit-http-security` : implementation for security filters for HTTP.
`hawkbit-rest-api` : API classes for the REST Management API.
`hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API.
`hawkbit-ui` : Vaadin UI.
`hawkbit-cache-redis` : spring cache manager configuration and implementation with redis, distributed cache and distributed events.
* `examples` : hawkBit examples
* `hawkbit-artifact-repository-mongo` : Artifact repository implementation to mongoDB.
* `hawkbit-autoconfigure` : Spring-boot auto-configuration.
* `hawkbit-cache-redis` : Spring cache manager configuration and implementation with redis, distributed cache and distributed events.
* `hawkbit-core` : Core elements for internal interfaces and utility classes.
* `hawkbit-ddi-api` : The hawkBit DDI API.
* `hawkbit-ddi-dl-api` : The hawkBit DDI Download API.
* `hawkbit-ddi-resource` : Implementation of the hawkBit DDI API
* `hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API.
* `hawkbit-dmf-api` : API for the Device Management Integration.
* `hawkbit-http-security` : Implementation for security filters for HTTP.
* `hawkbit-mgmt-api` : The hawkBit Management API
* `hawkbit-mgmt-resource` : Implementation of the hawkBit Management API
* `hawkbit-repository` : Repository implementation based on SQL for all meta-data.
* `hawkbit-rest-core` : Core elements for the rest modules.
* `hawkbit-security-core` : Core security elements.
* `hawkbit-security-integration` : Security integration elements to integrate security into hawkBit.
* `hawkbit-test-report` : Test reports
* `hawkbit-ui` : Vaadin UI.

20
deployHawkBitSandbox.sh Normal file
View File

@@ -0,0 +1,20 @@
#
# Copyright (c) 2015 Bosch Software Innovations 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
#
# This script allows the deployment of the complete hawkBit sandbox including
# data example to a cloud foundry enviroment. Expects existing CF CLI
# installation and login to be existing already.
cd examples/hawkbit-example-app/target/
cf push
cd ../..
java -jar hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-0.2.0-SNAPSHOT.jar --hawkbit.url=hawkbit.eu-gb.mybluemix.net
cd hawkbit-device-simulator/target/
cf push
cd ../../..

View File

@@ -1,7 +1,12 @@
# Examples
Example projects that show how hawkBit can be used to create, run or access an hawkBit empowered update server.
Example projects that show how _hawkBit_ can be used to create, run or access an _hawkBit_ empowered update server.
- `hawkbit-custom-theme-example` : Example for a customized theme for Management UI.
- `hawkbit-device-simulator` : Simulates device software updates, leveraging the hawkBit device integration options.
- `hawkbit-example-app` : Allows you to run the Spring Boot hawkBit app. Includes all _hawkBit_ interfaces, i.e. DDI, DMF, Mgmt-API, Mgmt-UI.
- `hawkbit-example-core-feign-client` : Core resources for the client examples.
- `hawkbit-example-ddi-feign-client` : Example _hawkBit_ DDI client based on the _hawkBit_ DDI API.
- `hawkbit-example-mgmt-feign-client` : Example _hawkBit_ Management client based on the _hawkBit_ Management API
- `hawkbit-example-mgmt-simulator` : Example client simulation for the _hawkBit_ Management API based on Spring Boot and the hawkbit-example-mgmt-feign-client.
`hawkbit-device-simulator` : Simulates device software updates, leveraging the hawkBit device integration options.
`hawkbit-example-app` : Allows you to run a Spring Boot and hawkBit based update server.
`hawkbit-mgmt-api-client` : Example client for the hawkBit management API.

View File

@@ -0,0 +1 @@
Theme customization example for Eclipse hawkBit. See wiki for the theme customization guide.

View File

@@ -0,0 +1,112 @@
<!--
Copyright (c) 2015 Bosch Software Innovations 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
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-custom-theme-example</artifactId>
<name>hawkBit :: Custom Theme Example App</name>
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.plugin.version}</version>
<configuration>
<warSourceDirectory>src/main/resources</warSourceDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>update-theme</goal>
<goal>compile-theme</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<outputDirectory>${baseDir}</outputDirectory>
<addResources>false</addResources>
<mainClass>org.eclipse.hawkbit.app.Start</mainClass>
<layout>JAR</layout>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Hawkbit -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-security-integration</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-http-security</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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.app;
import org.eclipse.hawkbit.ui.login.HawkbitLoginUI;
import org.eclipse.hawkbit.ui.themes.HawkbitTheme;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.spring.annotation.SpringUI;
/**
* Example hawkBit login UI implementation.
*
* A {@link SpringUI} annotated class must be present in the classpath for the
* login path. The easiest way to get an hawkBit login UI running is to extend
* the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in
* this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}.
*
*/
@SpringUI(path = HawkbitTheme.LOGIN_UI_PATH)
@Title("hawkBit Theme example")
@Theme(value = "exampletheme")
public class MyLoginUI extends HawkbitLoginUI {
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,45 @@
package org.eclipse.hawkbit.app;
/**
* Copyright (c) 2015 Bosch Software Innovations 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
*/
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.UIEventProvider;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.eventbus.EventBus;
import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.Transport;
import com.vaadin.spring.annotation.SpringUI;
/**
* Example hawkBit UI implementation.
*
* A {@link SpringUI} annotated class must be present in the classpath. The
* easiest way to get an hawkBit UI running is to extend the {@link HawkbitUI}
* and to annotated it with {@link SpringUI} as in this example.
*
*/
@SpringUI
@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET)
@Title("hawkBit Theme example")
@Theme(value = "exampletheme")
public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
@Autowired
public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus,
final UIEventProvider provider) {
super(new DelayedEventBusPushStrategy(eventBus, systemEventBus, provider));
}
}

View File

@@ -0,0 +1,39 @@
package org.eclipse.hawkbit.app;
/**
* Copyright (c) 2015 Bosch Software Innovations 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
*/
import org.eclipse.hawkbit.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
/**
* A {@link SpringBootApplication} annotated class with a main method to start.
* The minimal configuration for the stand alone hawkBit server.
*
*/
@SpringBootApplication
@Import({ RepositoryApplicationConfiguration.class })
@EnableHawkbitManagedSecurityConfiguration
// Exception squid:S1118 - Spring boot standard behavior
@SuppressWarnings({ "squid:S1118" })
public class Start {
/**
* Main method to start the spring-boot application.
*
* @param args
* the VM arguments.
*/
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) {
SpringApplication.run(Start.class, args);
}
}

View File

@@ -0,0 +1,2 @@
/addons.scss
/styles.css

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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
*/
$dark-gray: #848484;
//Example color change
$hawkbit-primary-color: $dark-gray;
$hawkbit-primary-color-light: #D8D8D8;
$app-selection-item-selection-color: $dark-gray;
$app-focus-color: $dark-gray;
$app-selection-color: $dark-gray;
$tag-text-color: $dark-gray;
$tab-sheet-caption-color: $dark-gray;
$table-details-tab-font-color: $dark-gray;
$widget-caption-color: $dark-gray;
$accordion-action-history-title-color: $dark-gray;
$menu-title-bg-color: $dark-gray;
$button-icon-color: $dark-gray;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,29 @@
<!--
Copyright (c) 2015 Bosch Software Innovations 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
-->
<head>
<style>
.footer-content {
margin-top: 20px ;
}
.doc-link {
color: #26547a !important;
text-decoration: none !important;
}
</style>
</head>
<footer>
<div class="footer-content">
<div style="color: #333; font-family: Helvetica Neue,Helvetica,Arial,sans-serif; font-size: 0.8em !important;line-height: 20px;">
<!-- Footer text goes here -->
<a class="doc-link" target="_blank" href="https://projects.eclipse.org/projects/iot.hawkbit">Eclipe hawkBit Project Page</a>
</div>
</div>
</footer>

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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
*/
@import "../hawkbit/customstyles/hawkbitvariables";
@import "customstyles/examplevariables";
@import "../hawkbit/hawkbittheme";
@import "addons";
// This file prefixes all rules with the theme name to avoid causing conflicts with other themes.
.exampletheme {
@include addons;
@include hawkbittheme;
}

View File

@@ -0,0 +1,16 @@
#
# Copyright (c) 2015 Bosch Software Innovations 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
#
# UI demo account
hawkbit.server.ui.demo.password=admin
hawkbit.server.ui.demo.user=admin
hawkbit.server.ui.demo.tenant=DEFAULT
# UI help links
hawkbit.server.ui.links.documentation.root=https://github.com/eclipse/hawkbit

View File

@@ -2,7 +2,7 @@
The device simulator handles software update commands from the update server.
## Run
## Run on your own workstation
```
java -jar examples/hawkbit-device-simulator/target/hawkbit-device-simulator-*-SNAPSHOT.jar
```
@@ -11,6 +11,11 @@ Or:
run org.eclipse.hawkbit.simulator.DeviceSimulator
```
## Deploy to cloud foundry environment
- Go to ```target``` subfolder.
- Run ```cf push```
## Notes
The simulator has user authentication enabled in **cloud profile**. Default credentials:
@@ -30,9 +35,9 @@ http://localhost:8083
```
![](src/main/images/generateScreenshot.png)
![](src/main/images/updateProcessScreenshot.png)
![](src/main/images/updateResultOverviewScreenshot.png)
@@ -54,12 +59,12 @@ Example: for 20 simulated devices (default)
http://localhost:8083/start
```
Example: for 10 simulated devices that start with the name prefix "activeSim":
Example: for 10 simulated devices that start with the name prefix "activeSim":
```
http://localhost:8083/start?amount=10&name=activeSim
```
Example: for 5 simulated devices that start with the name prefix "ddi" using the Direct Device Integration API (http):
Example: for 5 simulated devices that start with the name prefix "ddi" using the Direct Device Integration API (http):
```
http://localhost:8083/start?amount=5&name=ddi?api=ddi
```

View File

@@ -0,0 +1,22 @@
#
# Copyright (c) 2015 Bosch Software Innovations 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
#
---
applications:
- name: hawkbit-simulator
memory: 1024M
instances: 1
buildpack: https://github.com/cloudfoundry/java-buildpack
path: ${project.build.finalName}.jar
services:
- dmf-rabbit
env:
SPRING_PROFILES_ACTIVE: cloud,amqp
CF_STAGING_TIMEOUT: 15
CF_STARTUP_TIMEOUT: 15

View File

@@ -1,4 +1,3 @@
<?xml version="1.0"?>
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
@@ -9,7 +8,8 @@
http://www.eclipse.org/legal/epl-v10.html
-->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
<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>
@@ -19,7 +19,7 @@
</parent>
<artifactId>hawkbit-device-simulator</artifactId>
<name>hawkBit :: Device Simulator</name>
<name>hawkBit-example :: Device Simulator</name>
<description>Device Management Federation API based simulator</description>
<build>
@@ -42,6 +42,19 @@
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>cf</directory>
<filtering>true</filtering>
<targetPath>${project.build.directory}</targetPath>
<includes>
<include>manifest.yml</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
@@ -69,16 +82,26 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Log4j API and Core implementation required for binding -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<!-- Logging binding for java-util-logging e.g. Tomcat -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<!-- Logging binding for Jakarta Commons Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!-- Logging binding for Log4J Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
@@ -120,13 +143,17 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>7.6.3</version>
<version>${vaadin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.simulator;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
/**
* The bean of a simulated device which can be stored in the
* {@link DeviceSimulatorRepository} or shown in the UI.
@@ -22,16 +24,15 @@ public abstract class AbstractSimulatedDevice {
private Status status;
private double progress;
private String swversion = "unknown";
private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL;
private UpdateStatus updateStatus = new UpdateStatus(ResponseStatus.SUCCESSFUL, "Simulation complete!");
private Protocol protocol = Protocol.DMF_AMQP;
private String targetSecurityToken;
private int nextPollCounterSec;
/**
* Enum definition of the protocol to be used for the simulated device.
*
* @author Michael Hirsch
*
*/
public enum Protocol {
/**
@@ -69,24 +70,6 @@ public abstract class AbstractSimulatedDevice {
ERROR;
}
/**
* The status to response to the hawkbit update server if an simulated
* update process should be respond with successful or failure update.
*
* @author Michael Hirsch
*
*/
public enum ResponseStatus {
/**
* updated has been successful and response the successful update.
*/
SUCCESSFUL,
/**
* updated has been not successful and response the error update.
*/
ERROR;
}
/**
* empty constructor.
*/
@@ -158,12 +141,12 @@ public abstract class AbstractSimulatedDevice {
this.swversion = swversion;
}
public ResponseStatus getResponseStatus() {
return responseStatus;
public UpdateStatus getUpdateStatus() {
return updateStatus;
}
public void setResponseStatus(final ResponseStatus responseStatus) {
this.responseStatus = responseStatus;
public void setUpdateStatus(final UpdateStatus updateStatus) {
this.updateStatus = updateStatus;
}
public Protocol getProtocol() {
@@ -177,4 +160,13 @@ public abstract class AbstractSimulatedDevice {
public void setNextPollCounterSec(final int nextPollDelayInSec) {
this.nextPollCounterSec = nextPollDelayInSec;
}
public String getTargetSecurityToken() {
return targetSecurityToken;
}
public void setTargetSecurityToken(final String targetSecurityToken) {
this.targetSecurityToken = targetSecurityToken;
}
}

View File

@@ -8,8 +8,6 @@
*/
package org.eclipse.hawkbit.simulator;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.http.ControllerResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -18,7 +16,7 @@ import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
/**
* @author Michael Hirsch
* A simulated device using the DDI API of the hawkBit update server.
*
*/
public class DDISimulatedDevice extends AbstractSimulatedDevice {
@@ -26,12 +24,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class);
private final int pollDelaySec;
private final ScheduledExecutorService pollthreadpool;
private final ControllerResource controllerResource;
private final DeviceSimulatorUpdater deviceUpdater;
private volatile boolean removed;
private volatile Long currentActionId;
private final DeviceSimulatorUpdater deviceUpdater;
/**
* @param id
@@ -42,18 +40,14 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
* the delay of the poll interval in sec
* @param controllerResource
* the http controller resource
* @param pollthreadpool
* the threadpool for polling endpoint
* @param deviceUpdater
* the service to update devices
*/
public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec,
final ControllerResource controllerResource, final ScheduledExecutorService pollthreadpool,
final DeviceSimulatorUpdater deviceUpdater) {
final ControllerResource controllerResource, final DeviceSimulatorUpdater deviceUpdater) {
super(id, tenant, Protocol.DDI_HTTP);
this.pollDelaySec = pollDelaySec;
this.controllerResource = controllerResource;
this.pollthreadpool = pollthreadpool;
this.deviceUpdater = deviceUpdater;
setNextPollCounterSec(pollDelaySec);
}
@@ -76,27 +70,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
final String basePollJson = controllerResource.get(getTenant(), getId());
try {
final String href = JsonPath.parse(basePollJson).read("_links.deploymentBase.href");
final long actionId = Long.parseLong(href.substring(href.lastIndexOf("/") + 1, href.indexOf("?")));
final long actionId = Long.parseLong(href.substring(href.lastIndexOf('/') + 1, href.indexOf('?')));
if (currentActionId == null) {
final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId);
final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version");
currentActionId = actionId;
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, (device, actionId1) -> {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
controllerResource.postSuccessFeedback(getTenant(), getId(),
actionId1);
break;
case ERROR:
controllerResource.postErrorFeedback(getTenant(), getId(),
actionId1);
break;
default:
throw new IllegalStateException(
"simulated device has an unknown response status + " + device.getResponseStatus());
}
currentActionId = null;
});
startDdiUpdate(actionId, swVersion);
}
} catch (final PathNotFoundException e) {
// href might not be in the json response, so ignore
@@ -106,4 +85,21 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
}
}
private void startDdiUpdate(final long actionId, final String swVersion) {
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, null, null, (device, actionId1) -> {
switch (device.getUpdateStatus().getResponseStatus()) {
case SUCCESSFUL:
controllerResource.postSuccessFeedback(getTenant(), getId(), actionId1);
break;
case ERROR:
controllerResource.postErrorFeedback(getTenant(), getId(), actionId1);
break;
default:
throw new IllegalStateException("simulated device has an unknown response status + "
+ device.getUpdateStatus().getResponseStatus());
}
currentActionId = null;
});
}
}

View File

@@ -9,10 +9,7 @@
package org.eclipse.hawkbit.simulator;
/**
* An simulated device using the DMF API of the hawkbit update server.
*
* @author Michael Hirsch
*
* A simulated device using the DMF API of the hawkBit update server.
*/
public class DMFSimulatedDevice extends AbstractSimulatedDevice {

View File

@@ -21,8 +21,6 @@ import com.vaadin.spring.annotation.EnableVaadin;
/**
* The main-method to start the Spring-Boot application.
*
*
*
*/
@SpringBootApplication
@EnableVaadin
@@ -46,6 +44,8 @@ public class DeviceSimulator {
* @param args
* the args
*/
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) {
SpringApplication.run(DeviceSimulator.class, args);
}

View File

@@ -8,32 +8,65 @@
*/
package org.eclipse.hawkbit.simulator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.DigestOutputStream;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.eclipse.hawkbit.dmf.json.model.Artifact;
import org.eclipse.hawkbit.dmf.json.model.SoftwareModule;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
/**
* @author Michael Hirsch
* Update simulation handler.
*
*/
@Service
public class DeviceSimulatorUpdater {
private static final Logger LOGGER = LoggerFactory.getLogger(DeviceSimulatorUpdater.class);
private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4);
@Autowired
private SpSenderService spSenderService;
@Autowired
private SimulatedDeviceFactory deviceFactory;
@Autowired
private EventBus eventbus;
@@ -50,24 +83,43 @@ public class DeviceSimulatorUpdater {
* @param actionId
* the actionId from the hawkbit update server to start the
* update.
* @param swVersion
* @param modules
* the software module version from the hawkbit update server
* @param swVersion
* the software version as static value in case modules is null
* @param targetSecurityToken
* the target security token for download authentication
* @param callback
* the callback which gets called when the simulated update
* process has been finished
*/
public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion,
final UpdaterCallback callback) {
final AbstractSimulatedDevice device = repository.get(tenant, id);
final List<SoftwareModule> modules, final String targetSecurityToken, final UpdaterCallback callback) {
AbstractSimulatedDevice device = repository.get(tenant, id);
// plug and play - non existing device will be auto created
if (device == null) {
device = repository.add(deviceFactory.createSimulatedDevice(id, tenant, Protocol.DMF_AMQP, -1, null, null));
}
device.setProgress(0.0);
device.setSwversion(swVersion);
if (modules == null || modules.isEmpty()) {
device.setSwversion(swVersion);
} else {
device.setSwversion(modules.stream().map(sm -> sm.getModuleVersion()).collect(Collectors.joining(", ")));
}
device.setTargetSecurityToken(targetSecurityToken);
eventbus.post(new InitUpdate(device));
threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback),
2_000, TimeUnit.MILLISECONDS);
threadPool.schedule(
new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules), 2_000,
TimeUnit.MILLISECONDS);
}
private static final class DeviceSimulatorUpdateThread implements Runnable {
private static final int MINIMUM_TOKENLENGTH_FOR_HINT = 6;
private static final Random rndSleep = new SecureRandom();
private final AbstractSimulatedDevice device;
@@ -75,38 +127,211 @@ public class DeviceSimulatorUpdater {
private final long actionId;
private final EventBus eventbus;
private final UpdaterCallback callback;
private final List<SoftwareModule> modules;
private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService,
final long actionId, final EventBus eventbus, final UpdaterCallback callback) {
final long actionId, final EventBus eventbus, final UpdaterCallback callback,
final List<SoftwareModule> modules) {
this.device = device;
this.spSenderService = spSenderService;
this.actionId = actionId;
this.eventbus = eventbus;
this.callback = callback;
this.modules = modules;
}
@Override
public void run() {
if (device.getProgress() <= 0 && modules != null) {
device.setUpdateStatus(simulateDownloads(device.getTargetSecurityToken()));
if (isErrorResponse(device.getUpdateStatus())) {
callback.updateFinished(device, actionId);
eventbus.post(new ProgressUpdate(device));
return;
}
// download is 80% of the game after all
device.setProgress(0.8);
}
final double newProgress = device.getProgress() + 0.2;
device.setProgress(newProgress);
if (newProgress < 1.0) {
threadPool.schedule(
new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback),
new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules),
rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS);
} else {
callback.updateFinished(device, actionId);
}
eventbus.post(new ProgressUpdate(device));
}
private UpdateStatus simulateDownloads(final String targetToken) {
final List<UpdateStatus> status = new ArrayList<>();
LOGGER.info("Simulate downloads for {}", device.getId());
modules.forEach(module -> module.getArtifacts()
.forEach(artifact -> handleArtifacts(targetToken, status, artifact)));
final UpdateStatus result = new UpdateStatus(ResponseStatus.SUCCESSFUL);
result.getStatusMessages().add("Simulation complete!");
status.forEach(download -> {
result.getStatusMessages().addAll(download.getStatusMessages());
if (isErrorResponse(download)) {
result.setResponseStatus(ResponseStatus.ERROR);
}
});
LOGGER.info("Download simulations complete for {}", device.getId());
return result;
}
private boolean isErrorResponse(final UpdateStatus status) {
if (status == null) {
return false;
}
return ResponseStatus.ERROR.equals(status.getResponseStatus());
}
private static void handleArtifacts(final String targetToken, final List<UpdateStatus> status,
final Artifact artifact) {
artifact.getUrls().entrySet().forEach(entry -> {
switch (entry.getKey()) {
case HTTP:
case HTTPS:
status.add(downloadUrl(entry.getValue(), targetToken, artifact.getHashes().getSha1(),
artifact.getSize()));
break;
default:
// not supported yet
break;
}
});
}
private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash,
final long size) {
LOGGER.debug("Downloading {} with token {}, expected sha1 hash {} and size {}", url,
hideTokenDetails(targetToken), sha1Hash, size);
long overallread = 0;
try {
final CloseableHttpClient httpclient = createHttpClientThatAcceptsAllServerCerts();
final HttpGet request = new HttpGet(url);
request.addHeader(HttpHeaders.AUTHORIZATION, "TargetToken " + targetToken);
final String sha1HashResult;
try (final CloseableHttpResponse response = httpclient.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
final String message = wrongStatusCode(url, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
if (response.getEntity().getContentLength() != size) {
final String message = wrongContentLength(url, size, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
final File tempFile = File.createTempFile("uploadFile", null);
final MessageDigest md = MessageDigest.getInstance("SHA-1");
try (final DigestOutputStream dos = new DigestOutputStream(new FileOutputStream(tempFile), md)) {
try (final BufferedOutputStream bdos = new BufferedOutputStream(dos)) {
try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
overallread = ByteStreams.copy(bis, bdos);
}
}
} finally {
if (tempFile != null && !tempFile.delete()) {
LOGGER.error("Could not delete temporary file: {}", tempFile);
}
}
if (overallread != size) {
final String message = incompleteRead(url, size, overallread);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
sha1HashResult = BaseEncoding.base16().lowerCase().encode(md.digest());
}
if (!sha1Hash.equalsIgnoreCase(sha1HashResult)) {
final String message = wrongHash(url, sha1Hash, overallread, sha1HashResult);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
} catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
LOGGER.error("Failed to download" + url, e);
return new UpdateStatus(ResponseStatus.ERROR, "Failed to download " + url + ": " + e.getMessage());
}
final String message = "Downloaded " + url + " (" + overallread + " bytes)";
LOGGER.debug(message);
return new UpdateStatus(ResponseStatus.SUCCESSFUL, message);
}
private static String hideTokenDetails(final String targetToken) {
if (targetToken == null) {
return "<NULL!>";
}
if (targetToken.isEmpty()) {
return "<EMTPTY!>";
}
if (targetToken.length() <= MINIMUM_TOKENLENGTH_FOR_HINT) {
return "***";
}
return targetToken.substring(0, 2) + "***"
+ targetToken.substring(targetToken.length() - 2, targetToken.length());
}
private static String wrongHash(final String url, final String sha1Hash, final long overallread,
final String sha1HashResult) {
final String message = "Download " + url + " failed with SHA1 hash missmatch (Expected: " + sha1Hash
+ " but got: " + sha1HashResult + ") (" + overallread + " bytes)";
LOGGER.error(message);
return message;
}
private static String incompleteRead(final String url, final long size, final long overallread) {
final String message = "Download " + url + " is incomplete (Expected: " + size + " but got: " + overallread
+ ")";
LOGGER.error(message);
return message;
}
private static String wrongContentLength(final String url, final long size,
final CloseableHttpResponse response) {
final String message = "Download " + url + " has wrong content length (Expected: " + size + " but got: "
+ response.getEntity().getContentLength() + ")";
LOGGER.error(message);
return message;
}
private static String wrongStatusCode(final String url, final CloseableHttpResponse response) {
final String message = "Download " + url + " failed (" + response.getStatusLine().getStatusCode() + ")";
LOGGER.error(message);
return message;
}
private static CloseableHttpClient createHttpClientThatAcceptsAllServerCerts()
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
final SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, (chain, authType) -> true);
final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
}
/**
* Callback interface which is called when the simulated update process has
* been finished and the caller of starting the simulated update process can
* send the result to the hawkbit update server back.
*
* @author Michael Hirsch
*
* send the result back to the hawkBit update server.
*/
@FunctionalInterface
public interface UpdaterCallback {

View File

@@ -26,9 +26,6 @@ import com.google.common.eventbus.EventBus;
/**
* Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every
* second.
*
* @author Michael Hirsch
*
*/
@Component
public class NextPollTimeController {
@@ -59,16 +56,15 @@ public class NextPollTimeController {
devices.forEach(device -> {
int nextCounter = device.getNextPollCounterSec() - 1;
if (nextCounter < 0) {
if (device instanceof DDISimulatedDevice) {
try {
pollService.submit(() -> ((DDISimulatedDevice) device).poll());
} catch (final IllegalStateException e) {
LOGGER.trace("Device could not be polled", e);
}
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
if (nextCounter < 0 && device instanceof DDISimulatedDevice) {
try {
pollService.submit(() -> ((DDISimulatedDevice) device).poll());
} catch (final IllegalStateException e) {
LOGGER.trace("Device could not be polled", e);
}
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
}
device.setNextPollCounterSec(nextCounter);
});
eventBus.post(new NextPollCounterUpdate(devices));

View File

@@ -9,8 +9,6 @@
package org.eclipse.hawkbit.simulator;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.http.ControllerResource;
@@ -24,15 +22,9 @@ import feign.Logger;
/**
* The simulated device factory to create either {@link DMFSimulatedDevice} or
* {@link DDISimulatedDevice#}.
*
* @author Michael Hirsch
*
*/
@Service
public class SimulatedDeviceFactory {
private static final ScheduledExecutorService pollThreadPool = Executors.newScheduledThreadPool(4);
@Autowired
private DeviceSimulatorUpdater deviceUpdater;
@@ -47,7 +39,8 @@ public class SimulatedDeviceFactory {
* the protocol of the device
* @return the created simulated device
*/
public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol) {
public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant,
final Protocol protocol) {
return createSimulatedDevice(id, tenant, protocol, 30, null, null);
}
@@ -80,7 +73,7 @@ public class SimulatedDeviceFactory {
final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger())
.requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC)
.target(ControllerResource.class, baseEndpoint.toString());
return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, pollThreadPool, deviceUpdater);
return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, deviceUpdater);
default:
throw new IllegalArgumentException("Protocol " + protocol + " unknown");
}

View File

@@ -55,7 +55,7 @@ public class SimulationController {
* number of delay in milliseconds to delay polling of DDI
* devices
* @param gatewayToken
* the hawkbit-update-server gatwaytoken in case authentication
* the hawkbit-update-server gatewaytoken in case authentication
* is enforced in hawkbit
* @return a response string that devices has been created
* @throws MalformedURLException
@@ -68,7 +68,7 @@ public class SimulationController {
@RequestParam(value = "endpoint", defaultValue = "http://localhost:8080") final String endpoint,
@RequestParam(value = "polldelay", defaultValue = "30") final int pollDelay,
@RequestParam(value = "gatewaytoken", defaultValue = "") final String gatewayToken)
throws MalformedURLException {
throws MalformedURLException {
final Protocol protocol;
switch (api.toLowerCase()) {
@@ -86,7 +86,10 @@ public class SimulationController {
final String deviceId = name + i;
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint),
gatewayToken));
spSenderService.createOrUpdateThing(tenant, deviceId);
if (protocol == Protocol.DMF_AMQP) {
spSenderService.createOrUpdateThing(tenant, deviceId);
}
}
return ResponseEntity.ok("Updated " + amount + " DMF connected targets!");

View File

@@ -0,0 +1,136 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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.simulator;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* General simulator service properties.
*
*/
@Component
@ConfigurationProperties("hawkbit.device.simulator")
public class SimulationProperties {
/**
* List of tenants where the simulator should auto start simulations after
* startup.
*/
private final List<Autostart> autostarts = new ArrayList<>();
public List<Autostart> getAutostarts() {
return this.autostarts;
}
/**
* Auto start configuration for simulation setups that the simulator begins
* after startup.
*
*/
public static class Autostart {
/**
* Name prefix of simulated devices, followed by counter, e.g.
* simulated0, simulated1, simulated2....
*/
private String name = "simulated";
/**
* Amount of simulated devices.
*/
private int amount = 20;
/**
* Tenant name for the simulation.
*/
@NotEmpty
private String tenant;
/**
* API for simulation.
*/
private Protocol api = Protocol.DMF_AMQP;
/**
* Endpoint in case of DDI API based simulation.
*/
private String endpoint = "http://localhost:8080";
/**
* Poll time in case of DDI API based simulation.
*/
private int pollDelay = 30;
/**
* Optional gateway token for DDI API based simulation.
*/
private String gatewayToken = "";
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public int getAmount() {
return amount;
}
public void setAmount(final int amount) {
this.amount = amount;
}
public String getTenant() {
return tenant;
}
public void setTenant(final String tenant) {
this.tenant = tenant;
}
public Protocol getApi() {
return api;
}
public void setApi(final Protocol api) {
this.api = api;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(final String endpoint) {
this.endpoint = endpoint;
}
public int getPollDelay() {
return pollDelay;
}
public void setPollDelay(final int pollDelay) {
this.pollDelay = pollDelay;
}
public String getGatewayToken() {
return gatewayToken;
}
public void setGatewayToken(final String gatewayToken) {
this.gatewayToken = gatewayToken;
}
}
}

View File

@@ -0,0 +1,65 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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.simulator;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* Execution of operations after startup. Set up of simulations.
*
*/
@Component
@ConditionalOnProperty(prefix = "hawkbit.device.simulator", name = "autostart", matchIfMissing = true)
public class SimulatorStartup implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorStartup.class);
@Autowired
private SimulationProperties simulationProperties;
@Autowired
private SpSenderService spSenderService;
@Autowired
private DeviceSimulatorRepository repository;
@Autowired
private SimulatedDeviceFactory deviceFactory;
@Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
simulationProperties.getAutostarts().forEach(autostart -> {
for (int i = 0; i < autostart.getAmount(); i++) {
final String deviceId = autostart.getName() + i;
try {
repository.add(deviceFactory.createSimulatedDevice(deviceId, autostart.getTenant(),
autostart.getApi(), autostart.getPollDelay(), new URL(autostart.getEndpoint()),
autostart.getGatewayToken()));
} catch (final MalformedURLException e) {
LOGGER.error("Creation of simulated device at startup failed.", e);
}
if (autostart.getApi() == Protocol.DMF_AMQP) {
spSenderService.createOrUpdateThing(autostart.getTenant(), deviceId);
}
}
});
}
}

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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.simulator;
import java.util.ArrayList;
import java.util.List;
/**
* Update status of the simulated update.
*
*/
public class UpdateStatus {
private ResponseStatus responseStatus;
private List<String> statusMessages;
/**
* Constructor.
*
* @param responseStatus
* of the update
*/
public UpdateStatus(final ResponseStatus responseStatus) {
this.responseStatus = responseStatus;
}
/**
* Constructor including status message.
*
* @param responseStatus
* of the update
* @param message
* of the update status
*/
public UpdateStatus(final ResponseStatus responseStatus, final String message) {
this(responseStatus);
statusMessages = new ArrayList<>();
statusMessages.add(message);
}
public ResponseStatus getResponseStatus() {
return responseStatus;
}
public void setResponseStatus(final ResponseStatus responseStatus) {
this.responseStatus = responseStatus;
}
public List<String> getStatusMessages() {
if (statusMessages == null) {
statusMessages = new ArrayList<>();
}
return statusMessages;
}
/**
* The status to response to the hawkBit update server if an simulated
* update process should be respond with successful or failure update.
*/
public enum ResponseStatus {
/**
* Update has been successful and response the successful update.
*/
SUCCESSFUL,
/**
* Update has been not successful and response the error update.
*/
ERROR;
}
}

View File

@@ -59,7 +59,8 @@ public class AmqpConfiguration {
}
/**
* Create the receiver queue from sp. Receive messages from sp.
* Creates the receiver queue from update server for receiving message from
* update server.
*
* @return the queue
*/
@@ -70,7 +71,7 @@ public class AmqpConfiguration {
}
/**
* Create the recevier exchange. Sp send messages to this exchange.
* Creates the receiver exchange for sending messages to update server.
*
* @return the exchange
*/

View File

@@ -19,26 +19,31 @@ import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("hawkbit.device.simulator.amqp")
public class AmqpProperties {
/**
* Queue for receiving DMF messages from update server.
*/
private String receiverConnectorQueueFromSp;
private String receiverConnectorQueueFromSp = "simulator_receiver";
/**
* Exchange for sending DMF messages to update server.
*/
private String senderForSpExchange;
private String senderForSpExchange = "simulator.replyTo";
/**
* Simulator dead letter queue.
*/
private String deadLetterQueue;
private String deadLetterQueue = "simulator_deadletter";
/**
* Simulator dead letter exchange.
*/
private String deadLetterExchange;
private String deadLetterExchange = "simulator.deadletter";
/**
* Message time to live (ttl) for the deadletter queue. Default ttl is 1
* hour.
*/
private int deadLetterTtl = 60_000;
public String getReceiverConnectorQueueFromSp() {
return receiverConnectorQueueFromSp;
@@ -71,4 +76,12 @@ public class AmqpProperties {
public void setSenderForSpExchange(final String senderForSpExchange) {
this.senderForSpExchange = senderForSpExchange;
}
public int getDeadLetterTtl() {
return deadLetterTtl;
}
public void setDeadLetterTtl(final int deadLetterTtl) {
this.deadLetterTtl = deadLetterTtl;
}
}

View File

@@ -25,15 +25,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.google.common.collect.Lists;
/**
* Handle all incoming Messages from SP.
*
*
* Handle all incoming Messages from hawkBit update server.
*
*/
@Component
public class SpReceiverService extends ReceiverService {
private static final Logger LOGGER = LoggerFactory.getLogger(ReceiverService.class);
public static final String SOFTWARE_MODULE_FIRMWARE = "firmware";
@@ -44,17 +43,6 @@ public class SpReceiverService extends ReceiverService {
/**
* Constructor.
*
* @param rabbitTemplate
* the rabbit template
* @param amqpProperties
* the amqp properties
* @param lwm2mSenderService
* the lwm2mSenderService
* @param spSenderService
* the spSenderService
* @param deviceUpdater
* the updater service to simulate update process
*/
@Autowired
public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties,
@@ -62,12 +50,11 @@ public class SpReceiverService extends ReceiverService {
super(rabbitTemplate, amqpProperties);
this.spSenderService = spSenderService;
this.deviceUpdater = deviceUpdater;
}
/**
* Handle the incoming Message from Queue with the property
* (com.bosch.sp.lwm2m.connector.amqp.receiverConnectorQueueFromSp).
* (hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp).
*
* @param message
* the incoming message
@@ -103,6 +90,8 @@ public class SpReceiverService extends ReceiverService {
if (eventHeader == null) {
logAndThrowMessageError(message, "Event Topic is not set");
}
// Exception squid:S2259 - Checked before
@SuppressWarnings({ "squid:S2259" })
final EventTopic eventTopic = EventTopic.valueOf(eventHeader.toString());
switch (eventTopic) {
case DOWNLOAD_AND_INSTALL:
@@ -124,7 +113,7 @@ public class SpReceiverService extends ReceiverService {
final Long actionId = convertMessage(message, Long.class);
final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId);
spSenderService.finishUpdateProcess(update, "Simulation canceled");
spSenderService.finishUpdateProcess(update, Lists.newArrayList("Simulation canceled"));
}
private void handleUpdateProcess(final Message message, final String thingId) {
@@ -135,19 +124,20 @@ public class SpReceiverService extends ReceiverService {
final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message,
DownloadAndUpdateRequest.class);
final Long actionId = downloadAndUpdateRequest.getActionId();
final String targetSecurityToken = downloadAndUpdateRequest.getTargetSecurityToken();
deviceUpdater.startUpdate(tenant, thingId, actionId,
downloadAndUpdateRequest.getSoftwareModules().get(0).getModuleVersion(), (device, actionId1) -> {
switch (device.getResponseStatus()) {
deviceUpdater.startUpdate(tenant, thingId, actionId, null, downloadAndUpdateRequest.getSoftwareModules(),
targetSecurityToken, (device, actionId1) -> {
switch (device.getUpdateStatus().getResponseStatus()) {
case SUCCESSFUL:
spSenderService.finishUpdateProcess(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete!");
device.getUpdateStatus().getStatusMessages());
break;
case ERROR:
spSenderService.finishUpdateProcessWithError(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete with error!");
device.getUpdateStatus().getStatusMessages());
break;
default:
break;

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import java.util.List;
import java.util.Map;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
@@ -23,13 +24,9 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
/**
* Sender service to send message to SP.
*
*
*
* Sender service to send messages to update server.
*/
@Service
public class SpSenderService extends SenderService {
@@ -59,8 +56,9 @@ public class SpSenderService extends SenderService {
* @param description
* a description according the update process
*/
public void finishUpdateProcess(final SimulatedUpdate update, final String description) {
final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED, description);
public void finishUpdateProcess(final SimulatedUpdate update, final List<String> updateResultMessages) {
final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED,
updateResultMessages);
sendMessage(spExchange, updateResultMessage);
}
@@ -72,9 +70,9 @@ public class SpSenderService extends SenderService {
* @param messageDescription
* a description according the update process
*/
public void finishUpdateProcessWithError(final SimulatedUpdate update, final String messageDescription) {
sendErrorgMessage(update, messageDescription);
LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", messageDescription,
public void finishUpdateProcessWithError(final SimulatedUpdate update, final List<String> updateResultMessages) {
sendErrorgMessage(update, updateResultMessages);
LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", updateResultMessages,
update.getThingId());
}
@@ -88,8 +86,8 @@ public class SpSenderService extends SenderService {
* @param actionId
* the ID of the action for the error message
*/
public void sendErrorMessage(final String tenant, final String messageDescription, final Long actionId) {
final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, messageDescription, actionId);
public void sendErrorMessage(final String tenant, final List<String> updateResultMessages, final Long actionId) {
final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, updateResultMessages, actionId);
sendMessage(spExchange, message);
}
@@ -101,8 +99,8 @@ public class SpSenderService extends SenderService {
* @param warningMessage
* a warning description
*/
public void sendWarningMessage(final SimulatedUpdate update, final String warningMessage) {
final Message message = createActionStatusMessage(update, warningMessage, ActionStatus.WARNING);
public void sendWarningMessage(final SimulatedUpdate update, final List<String> updateResultMessages) {
final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.WARNING);
sendMessage(spExchange, message);
}
@@ -119,8 +117,8 @@ public class SpSenderService extends SenderService {
* the cached value
*/
public void sendActionStatusMessage(final String tenant, final ActionStatus actionStatus,
final String actionMessage, final Long actionId) {
final Message message = createActionStatusMessage(tenant, actionStatus, actionMessage, actionId);
final List<String> updateResultMessages, final Long actionId) {
final Message message = createActionStatusMessage(tenant, actionStatus, updateResultMessages, actionId);
sendMessage(message);
}
@@ -162,11 +160,11 @@ public class SpSenderService extends SenderService {
*
* @param context
* the current context
* @param messageDescription
* a description according the update process
* @param updateResultMessages
* a list of descriptions according the update process
*/
private void sendErrorgMessage(final SimulatedUpdate update, final String messageDescription) {
final Message message = createActionStatusMessage(update, messageDescription, ActionStatus.ERROR);
private void sendErrorgMessage(final SimulatedUpdate update, final List<String> updateResultMessages) {
final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.ERROR);
sendMessage(spExchange, message);
}
@@ -183,7 +181,7 @@ public class SpSenderService extends SenderService {
* the cacheValue value
*/
private Message createActionStatusMessage(final String tenant, final ActionStatus actionStatus,
final String actionMessage, final Long actionId) {
final List<String> updateResultMessages, final Long actionId) {
final MessageProperties messageProperties = new MessageProperties();
final Map<String, Object> headers = messageProperties.getHeaders();
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
@@ -192,15 +190,14 @@ public class SpSenderService extends SenderService {
headers.put(MessageHeaderKey.TENANT, tenant);
headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON);
if (!StringUtils.isEmpty(actionMessage)) {
actionUpdateStatus.getMessage().add(actionMessage);
}
actionUpdateStatus.getMessage().addAll(updateResultMessages);
actionUpdateStatus.setActionId(actionId);
return convertMessage(actionUpdateStatus, messageProperties);
}
private Message createUpdateResultMessage(final SimulatedUpdate cacheValue, final ActionStatus actionStatus,
final String updateResultMessage) {
final List<String> updateResultMessages) {
final MessageProperties messageProperties = new MessageProperties();
final Map<String, Object> headers = messageProperties.getHeaders();
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
@@ -209,14 +206,14 @@ public class SpSenderService extends SenderService {
headers.put(MessageHeaderKey.TENANT, cacheValue.getTenant());
headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON);
actionUpdateStatus.getMessage().add(updateResultMessage);
actionUpdateStatus.getMessage().addAll(updateResultMessages);
actionUpdateStatus.setActionId(cacheValue.getActionId());
return convertMessage(actionUpdateStatus, messageProperties);
}
private Message createActionStatusMessage(final SimulatedUpdate update, final String messageDescription,
private Message createActionStatusMessage(final SimulatedUpdate update, final List<String> updateResultMessages,
final ActionStatus status) {
return createActionStatusMessage(update.getTenant(), status, messageDescription, update.getActionId());
return createActionStatusMessage(update.getTenant(), status, updateResultMessages, update.getActionId());
}
}

View File

@@ -13,8 +13,6 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
/**
* Event definition object which is published if the simulated device updated
* its update progress.
*
* @author Michael Hirsch
*
*/
public class ProgressUpdate {

View File

@@ -8,21 +8,19 @@
*/
package org.eclipse.hawkbit.simulator.ui;
import java.net.URL;
import java.util.List;
import java.util.Locale;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.ResponseStatus;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Status;
import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
import org.eclipse.hawkbit.simulator.ui.GenerateDialog.GenerateDialogCallback;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.collect.Lists;
@@ -52,13 +50,29 @@ import com.vaadin.ui.renderers.ProgressBarRenderer;
* Vaadin view which allows to generate devices through the DMF API and show the
* current simulated devices in a grid with their current status and update
* progress.
*
* @author Michael Hirsch
*
*/
@SpringView(name = "")
// The inheritance comes from Vaadin
@SuppressWarnings("squid:MaximumInheritanceDepth")
public class SimulatorView extends VerticalLayout implements View {
private static final String NEXT_POLL_COUNTER_SEC_COL = "nextPollCounterSec";
private static final String RESPONSE_STATUS_COL = "updateStatus";
private static final String PROTOCOL_COL = "protocol";
private static final String TENANT_COL = "tenant";
private static final String PROGRESS_COL = "progress";
private static final String SWVERSION_COL = "swversion";
private static final String STATUS_COL = "status";
private static final String ID_COL = "id";
private static final long serialVersionUID = 1L;
@Autowired
@@ -79,6 +93,7 @@ public class SimulatorView extends VerticalLayout implements View {
private BeanContainer<String, AbstractSimulatedDevice> beanContainer;
@SuppressWarnings("unchecked")
@Override
public void enter(final ViewChangeEvent event) {
eventbus.register(this);
@@ -91,7 +106,7 @@ public class SimulatorView extends VerticalLayout implements View {
createToolbar();
beanContainer = new BeanContainer<>(AbstractSimulatedDevice.class);
beanContainer.setBeanIdProperty("id");
beanContainer.setBeanIdProperty(ID_COL);
grid.setSizeFull();
grid.setCellStyleGenerator(new CellStyleGenerator() {
@@ -100,38 +115,37 @@ public class SimulatorView extends VerticalLayout implements View {
@Override
public String getStyle(final CellReference cellReference) {
return cellReference.getPropertyId().equals("status") ? "centeralign" : null;
return cellReference.getPropertyId().equals(STATUS_COL) ? "centeralign" : null;
}
});
grid.setSelectionMode(SelectionMode.NONE);
grid.setContainerDataSource(beanContainer);
grid.appendHeaderRow().getCell("responseStatus").setComponent(responseComboBox);
grid.setColumnOrder("id", "status", "swversion", "progress", "tenant", "protocol", "responseStatus",
"nextPollCounterSec");
grid.appendHeaderRow().getCell(RESPONSE_STATUS_COL).setComponent(responseComboBox);
grid.setColumnOrder(ID_COL, STATUS_COL, SWVERSION_COL, PROGRESS_COL, TENANT_COL, PROTOCOL_COL,
RESPONSE_STATUS_COL, NEXT_POLL_COUNTER_SEC_COL);
// header widths
grid.getColumn("status").setMaximumWidth(80);
grid.getColumn("protocol").setMaximumWidth(180);
grid.getColumn("responseStatus").setMaximumWidth(240);
grid.getColumn("nextPollCounterSec").setMaximumWidth(210);
grid.getColumn(STATUS_COL).setMaximumWidth(80);
grid.getColumn(PROTOCOL_COL).setMaximumWidth(180);
grid.getColumn(RESPONSE_STATUS_COL).setMaximumWidth(240);
grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).setMaximumWidth(210);
grid.getColumn("nextPollCounterSec").setHeaderCaption("Next Poll in (sec)");
grid.getColumn("swversion").setHeaderCaption("SW Version");
grid.getColumn("responseStatus").setHeaderCaption("Response Update Status");
grid.getColumn("progress").setRenderer(new ProgressBarRenderer());
grid.getColumn("protocol").setConverter(createProtocolConverter());
grid.getColumn("status").setRenderer(new HtmlRenderer(), createStatusConverter());
grid.removeColumn("tenant");
grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).setHeaderCaption("Next Poll in (sec)");
grid.getColumn(SWVERSION_COL).setHeaderCaption("SW Version");
grid.getColumn(RESPONSE_STATUS_COL).setHeaderCaption("Response Update Status");
grid.getColumn(PROGRESS_COL).setRenderer(new ProgressBarRenderer());
grid.getColumn(PROTOCOL_COL).setConverter(createProtocolConverter());
grid.getColumn(STATUS_COL).setRenderer(new HtmlRenderer(), createStatusConverter());
grid.removeColumn(TENANT_COL);
// grid combobox
responseComboBox.setItemIcon(ResponseStatus.SUCCESSFUL, FontAwesome.CHECK_CIRCLE);
responseComboBox.setItemIcon(ResponseStatus.ERROR, FontAwesome.EXCLAMATION_CIRCLE);
responseComboBox.setNullSelectionAllowed(false);
responseComboBox.setValue(ResponseStatus.SUCCESSFUL);
responseComboBox.addValueChangeListener(valueChangeEvent -> {
beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus")
.setValue(valueChangeEvent.getProperty().getValue()));
});
responseComboBox.addValueChangeListener(
valueChangeEvent -> beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId)
.getItemProperty(RESPONSE_STATUS_COL).setValue(valueChangeEvent.getProperty().getValue())));
// add all components
addComponent(caption);
@@ -141,7 +155,7 @@ public class SimulatorView extends VerticalLayout implements View {
setExpandRatio(grid, 1.0F);
// load beans
repository.getAll().forEach(device -> beanContainer.addBean(device));
repository.getAll().forEach(beanContainer::addBean);
}
@Override
@@ -150,20 +164,16 @@ public class SimulatorView extends VerticalLayout implements View {
eventbus.unregister(this);
}
@SuppressWarnings("unchecked")
@Subscribe
public void pollCounterUpdate(final NextPollCounterUpdate update) {
final List<AbstractSimulatedDevice> devices = update.getDevices();
this.getUI().access(new Runnable() {
@Override
public void run() {
devices.forEach(device -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("nextPollCounterSec").setValue(device.getNextPollCounterSec());
}
});
this.getUI().access(() -> devices.forEach(device -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty(NEXT_POLL_COUNTER_SEC_COL).setValue(device.getNextPollCounterSec());
}
});
}));
}
/**
@@ -172,20 +182,19 @@ public class SimulatorView extends VerticalLayout implements View {
* @param update
* the update event posted on the event bus
*/
@SuppressWarnings("unchecked")
@Subscribe
public void initUpdate(final InitUpdate update) {
final AbstractSimulatedDevice device = update.getDevice();
this.getUI().access(new Runnable() {
@Override
public void run() {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("progress").setValue(device.getProgress());
item.getItemProperty("status").setValue(Status.PEDNING);
item.getItemProperty("swversion").setValue(device.getSwversion());
}
this.getUI().access(() -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item == null) {
return;
}
item.getItemProperty(PROGRESS_COL).setValue(device.getProgress());
item.getItemProperty(STATUS_COL).setValue(Status.PEDNING);
item.getItemProperty(SWVERSION_COL).setValue(device.getSwversion());
});
}
@@ -195,35 +204,37 @@ public class SimulatorView extends VerticalLayout implements View {
* @param update
* the update event posted on the event bus
*/
@SuppressWarnings("unchecked")
@Subscribe
public void progessUpdate(final ProgressUpdate update) {
final AbstractSimulatedDevice device = update.getDevice();
this.getUI().access(new Runnable() {
@Override
public void run() {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("progress").setValue(device.getProgress());
if (device.getProgress() >= 1) {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
item.getItemProperty("status").setValue(Status.FINISH);
break;
case ERROR:
item.getItemProperty("status").setValue(Status.ERROR);
break;
default:
item.getItemProperty("status").setValue(Status.UNKNWON);
}
} else {
item.getItemProperty("status").setValue(Status.PEDNING);
}
}
this.getUI().access(() -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty(PROGRESS_COL).setValue(device.getProgress());
setStatusColumn(device, item);
}
});
}
@SuppressWarnings("unchecked")
private void setStatusColumn(final AbstractSimulatedDevice device, final BeanItem<AbstractSimulatedDevice> item) {
if (device.getProgress() >= 1) {
switch (device.getUpdateStatus().getResponseStatus()) {
case SUCCESSFUL:
item.getItemProperty(STATUS_COL).setValue(Status.FINISH);
break;
case ERROR:
item.getItemProperty(STATUS_COL).setValue(Status.ERROR);
break;
default:
item.getItemProperty(STATUS_COL).setValue(Status.UNKNWON);
}
} else {
item.getItemProperty(STATUS_COL).setValue(Status.PEDNING);
}
}
private void createToolbar() {
final Button createDevicesButton = new Button("generate...");
createDevicesButton.setIcon(FontAwesome.GEARS);
@@ -244,18 +255,15 @@ public class SimulatorView extends VerticalLayout implements View {
}
private void openGenerateDialog() {
UI.getCurrent().addWindow(new GenerateDialog(new GenerateDialogCallback() {
@Override
public void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay,
final URL basePollUrl, final String gatewayToken, final Protocol protocol) {
for (int index = 0; index < amount; index++) {
final String deviceId = namePrefix + index;
beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId,
tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken)));
spSenderService.createOrUpdateThing(tenant, deviceId);
}
}
}));
UI.getCurrent().addWindow(
new GenerateDialog((namePrefix, tenant, amount, pollDelay, basePollUrl, gatewayToken, protocol) -> {
for (int index = 0; index < amount; index++) {
final String deviceId = namePrefix + index;
beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId,
tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken)));
spSenderService.createOrUpdateThing(tenant, deviceId);
}
}));
}
private Converter<String, Protocol> createProtocolConverter() {

View File

@@ -7,18 +7,17 @@
# http://www.eclipse.org/legal/epl-v10.html
#
#########################################################################################
# PUBLIC configuration, i.e. can be changed by users at runtime (defaults provided here)
#########################################################################################
## Configuration for RabbitMQ communication
## Configuration for DMF communication
hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp=simulator_receiver
hawkbit.device.simulator.amqp.deadLetterQueue=simulator_deadletter
hawkbit.device.simulator.amqp.deadLetterExchange=simulator.deadletter
hawkbit.device.simulator.amqp.senderForSpExchange=simulator.replyTo
## Configuration for simulations
hawkbit.device.simulator.autostarts.[0].tenant=DEFAULT
## Configuration for RabbitMQ integration
## Configuration for local RabbitMQ integration
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtualHost=/

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015 Bosch Software Innovations 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
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit.eventbus.DeadEventListener" level="WARN" />
<Logger name="org.springframework.boot.actuate.audit.listener.AuditListener" level="WARN" />
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN" />
<Logger name="org.apache.tomcat.jdbc.pool.ConnectionPool" level="DEBUG" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR" />
<!-- Security Log with hints on potential attacks -->
<logger name="server-security" level="INFO" />
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</configuration>

View File

@@ -1,15 +1,35 @@
# hawkBit Example Application
The hawkBit example application is a standalone spring-boot application with an embedded servlet container to start the hawkBit.
The hawkBit example application is a standalone spring-boot application with an embedded servlet container to host the hawkBit Update Server.
## Run
We have have described several options for you to get access to the example.
## Try out the example application in our hawkBit sandbox on Bluemix
- try out Management UI https://hawkbit.eu-gb.mybluemix.net/UI (username: admin, passwd: admin)
- try out Management API https://hawkbit.eu-gb.mybluemix.net/rest/v1/targets (don't forget basic auth header; username: admin, passwd: admin)
- try out DDI API https://hawkbit.eu-gb.mybluemix.net/DEFAULT/controller/v1/MYTESTDEVICE (authentication disabled)
## On your own workstation
### Run
```
java -jar examples/hawkbit-example-app/target/hawkbit-example-app-*-SNAPSHOT.jar
```
_(Note: you have to add the JDBC driver also to your class path if you intend to use another database than H2.)_
Or:
```
run org eclipse.hawkbit.app.Start
```
## Usage
The UI can be accessed via _http://localhost:8080/UI_.
The REST API can be accessed via _http://localhost:8080/rest/v1_.
### Usage
The Management UI can be accessed via http://localhost:8080/UI
The Management API can be accessed via http://localhost:8080/rest/v1
## Deploy example app to Cloud Foundry
- Go to ```target``` subfolder.
- Select one of the two manifests
- **manifest-simple.yml** for a standalone hawkBit installation with embedded H2.
- **manifest.yml** for a standalone hawkBit installation with embedded H2 and RabbitMQ service binding for DMF integration (note: this manifest is used for the sandbox above).
- Run ```cf push``` against you cloud foundry environment.

View File

@@ -0,0 +1,20 @@
#
# Copyright (c) 2015 Bosch Software Innovations 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
#
---
applications:
- name: hawkbit-simple
memory: 1024M
instances: 1
buildpack: https://github.com/cloudfoundry/java-buildpack
path: ${project.build.finalName}.jar
env:
SPRING_PROFILES_ACTIVE: cloudsandbox
CF_STAGING_TIMEOUT: 15
CF_STARTUP_TIMEOUT: 15

View File

@@ -0,0 +1,22 @@
#
# Copyright (c) 2015 Bosch Software Innovations 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
#
---
applications:
- name: hawkbit
memory: 1024M
instances: 1
buildpack: https://github.com/cloudfoundry/java-buildpack
path: ${project.build.finalName}.jar
services:
- dmf-rabbit
env:
SPRING_PROFILES_ACTIVE: cloudsandbox,amqp
CF_STAGING_TIMEOUT: 15
CF_STARTUP_TIMEOUT: 15

View File

@@ -17,7 +17,7 @@
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-example-app</artifactId>
<name>hawkBit :: Example App</name>
<name>hawkBit-example :: UI Application</name>
<build>
<plugins>
@@ -39,6 +39,20 @@
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>cf</directory>
<filtering>true</filtering>
<targetPath>${project.build.directory}</targetPath>
<includes>
<include>manifest.yml</include>
<include>manifest-simple.yml</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
@@ -50,7 +64,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-rest-resource</artifactId>
<artifactId>hawkbit-mgmt-resource</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ddi-resource</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@@ -82,16 +101,26 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Log4j API and Core implementation required for binding -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<!-- Logging binding for java-util-logging e.g. Tomcat -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<!-- Logging binding for Jakarta Commons Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!-- Logging binding for Log4J Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>

View File

@@ -20,11 +20,11 @@ import com.vaadin.spring.annotation.SpringUI;
* login path. The easiest way to get an hawkBit login UI running is to extend
* the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in
* this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}.
*
*
*
*/
@SpringUI(path = HawkbitTheme.LOGIN_UI_PATH)
// Exception squid:MaximumInheritanceDepth - Most of the inheritance comes from
// Vaadin.
@SuppressWarnings({ "squid:MaximumInheritanceDepth" })
public class MyLoginUI extends HawkbitLoginUI {
private static final long serialVersionUID = 1L;

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.app;
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.UIEventProvider;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,12 +29,16 @@ import com.vaadin.spring.annotation.SpringUI;
*/
@SpringUI
@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET)
// Exception squid:MaximumInheritanceDepth - Most of the inheritance comes from
// Vaadin.
@SuppressWarnings({ "squid:MaximumInheritanceDepth" })
public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
@Autowired
public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus) {
super(new DelayedEventBusPushStrategy(eventBus, systemEventBus));
public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus,
final UIEventProvider provider) {
super(new DelayedEventBusPushStrategy(eventBus, systemEventBus, provider));
}
}

View File

@@ -10,8 +10,8 @@ package org.eclipse.hawkbit.app;
import org.eclipse.hawkbit.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
import org.eclipse.hawkbit.controller.EnableDirectDeviceApi;
import org.eclipse.hawkbit.rest.resource.EnableRestResources;
import org.eclipse.hawkbit.ddi.EnableDdiApi;
import org.eclipse.hawkbit.mgmt.EnableMgmtApi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@@ -24,8 +24,10 @@ import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import({ RepositoryApplicationConfiguration.class })
@EnableHawkbitManagedSecurityConfiguration
@EnableRestResources
@EnableDirectDeviceApi
@EnableMgmtApi
@EnableDdiApi
// Exception squid:S1118 - Spring boot standard behavior
@SuppressWarnings({ "squid:S1118" })
public class Start {
/**
@@ -34,6 +36,8 @@ public class Start {
* @param args
* the VM arguments.
*/
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) {
SpringApplication.run(Start.class, args);
}

View File

@@ -0,0 +1,16 @@
#
# Copyright (c) 2015 Bosch Software Innovations 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
#
vaadin.servlet.productionMode=true
hawkbit.artifact.url.coap.enabled=false
hawkbit.artifact.url.http.enabled=false
hawkbit.artifact.url.https.enabled=true
hawkbit.artifact.url.https.pattern={protocol}://{hostname}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
hawkbit.artifact.url.https.hostname=hawkbit.eu-gb.mybluemix.net

View File

@@ -0,0 +1,32 @@
#
# Copyright (c) 2015 Bosch Software Innovations 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
#
# This profile adds basic configurations for a MySQL DB usage.
# Keep in mind that you need the MariaDB driver in your classpath on compile.
# see https://github.com/eclipse/hawkbit/wiki/Run-hawkBit
spring.jpa.database=MYSQL
spring.datasource.url=jdbc:mysql://localhost:3306/hawkbit
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driverClassName=org.mariadb.jdbc.Driver
spring.datasource.max-active=100
spring.datasource.max-idle=10
spring.datasource.min-idle=10
spring.datasource.initial-size=10
spring.datasource.validation-query=select 1 from dual
spring.datasource.validation-interval=30000
spring.datasource.test-on-borrow=true
spring.datasource.test-on-return=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=30000
spring.datasource.min-evictable-idle-time-millis=60000
spring.datasource.max-wait=10000
spring.datasource.jmx-enabled=true

View File

@@ -7,21 +7,28 @@
# http://www.eclipse.org/legal/epl-v10.html
#
# DDI authentication configuration
hawkbit.server.ddi.security.authentication.anonymous.enabled=true
hawkbit.server.ddi.security.authentication.targettoken.enabled=false
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false
hawkbit.server.ddi.security.authentication.targettoken.enabled=true
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=true
spring.profiles.active=amqp
# Download URL generation config
hawkbit.artifact.url.coap.enabled=false
hawkbit.artifact.url.http.enabled=true
hawkbit.artifact.url.http.port=8080
hawkbit.artifact.url.https.enabled=false
## Vaadin configuration
vaadin.servlet.productionMode=false
## Configuration for RabbitMQ integration
## Configuration for DMF/RabbitMQ integration
spring.profiles.active=amqp
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtualHost=/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter_ttl
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015 Bosch Software Innovations 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
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit.eventbus.DeadEventListener" level="WARN" />
<Logger name="org.springframework.boot.actuate.audit.listener.AuditListener" level="WARN" />
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN" />
<Logger name="org.apache.tomcat.jdbc.pool.ConnectionPool" level="DEBUG" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR" />
<!-- Security Log with hints on potential attacks -->
<logger name="server-security" level="INFO" />
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</configuration>

View File

@@ -0,0 +1,13 @@
# Eclipse.IoT hawkBit - Example Core Feign Client
This modules contains core beans that are needed to create a [Feign Client](https://github.com/Netflix/feign) with hwakBit.
# Compile
#### Build hawkbit-example-core-feign-client
```
$ cd hawkbit/examples/hawkbit-example-core-feign-client
$ mvn clean install
```

View File

@@ -0,0 +1,46 @@
<!--
Copyright (c) 2015 Bosch Software Innovations 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
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-example-core-feign-client</artifactId>
<name>hawkBit-example :: Feign Core Client</name>
<dependencies>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-core</artifactId>
<version>1.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-slf4j</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client;
package org.eclipse.hawkbit.feign.core.client;
import org.springframework.http.MediaType;

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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.feign.core.client;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.netflix.feign.FeignClientsConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import feign.Contract;
import feign.Feign;
/**
* Spring annotated java configuration class which defines necessary beans for
* configure the feign-client.
*/
@Configuration
@ConditionalOnClass(Feign.class)
@Import(FeignClientsConfiguration.class)
public class FeignClientConfiguration {
@Bean
public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() {
return new ApplicationJsonRequestHeaderInterceptor();
}
@Bean
public Contract feignContract() {
return new IgnoreMultipleConsumersProducersSpringMvcContract();
}
}

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client;
package org.eclipse.hawkbit.feign.core.client;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

View File

@@ -0,0 +1,14 @@
# Eclipse.IoT hawkBit - Example DDI Feign Client API
This modules contains the declarative client binding resources of the DDI API.
For more information see 'Feign Inheritance Support' at [Spring Cloud] (http://projects.spring.io/spring-cloud/spring-cloud.html).
Powered by [Feign](https://github.com/Netflix/feign).
# Compile
#### Build hawkbit-example-ddi-feign-client
```
$ cd hawkbit/examples/hawkbit-example-ddi-feign-client
$ mvn clean install
```

View File

@@ -0,0 +1,68 @@
<!--
Copyright (c) 2015 Bosch Software Innovations 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
-->
<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-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-example-ddi-feign-client</artifactId>
<name>hawkBit-example :: DDI Feign Client</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.0.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-example-core-feign-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ddi-dl-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ddi-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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.ddi.client.resource;
import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlArtifactStoreControllerRestApi;
import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlRestConstants;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the artifact store controller resource of the DDI-DL API.
*/
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + DdiDlRestConstants.ARTIFACTS_V1_REQUEST_MAPPING)
public interface DdiDlArtifactStoreControllerResourceClient extends DdiDlArtifactStoreControllerRestApi {
}

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2015 Bosch Software Innovations 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.ddi.client.resource;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.ddi.rest.api.DdiRootControllerRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the Rootcontroller resource of the DDI API.
*/
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + DdiRestConstants.BASE_V1_REQUEST_MAPPING)
public interface RootControllerResourceClient extends DdiRootControllerRestApi {
}

View File

@@ -0,0 +1,15 @@
# Eclipse.IoT hawkBit - Example Management Feign Client API
This modules contains the declarative client binding resources of the Management API.
For more information see 'Feign Inheritance Support' at [Spring Cloud] (http://projects.spring.io/spring-cloud/spring-cloud.html).
Powered by [Feign](https://github.com/Netflix/feign).
# Compile
#### Build hawkbit-example-mgmt-feign-client
```
$ cd hawkbit/examples/hawkbit-example-mgmt-feign-client
$ mvn clean install
```

View File

@@ -0,0 +1,56 @@
<!--
Copyright (c) 2015 Bosch Software Innovations 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
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<artifactId>hawkbit-example-mgmt-feign-client</artifactId>
<name>hawkBit-example :: Management client API</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-example-core-feign-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-mgmt-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<!-- need to overwrite for the interface inheritance feature of feign-core -->
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate</groupId>
</dependency>
</dependencies>
</project>

View File

@@ -8,13 +8,14 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.DistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the DistributionSet resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsets")
public interface DistributionSetResourceClient extends DistributionSetRestApi {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)
public interface MgmtDistributionSetClientResource extends MgmtDistributionSetRestApi {
}

View File

@@ -8,13 +8,13 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.DistributionSetTagRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the DistributionSetTag resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsettags")
public interface DistributionSetTagResourceClient extends DistributionSetTagRestApi {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
public interface MgmtDistributionSetTagClientResource extends MgmtDistributionSetTagRestApi {
}

View File

@@ -8,14 +8,15 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.DistributionSetTypeRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the DistributionSetType resource of the management API.
*
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsettypes")
public interface DistributionSetTypeResourceClient extends DistributionSetTypeRestApi {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)
public interface MgmtDistributionSetTypeClientResource extends MgmtDistributionSetTypeRestApi {
}

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadArtifactRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* A feign-client interface declaration which allows to build a feign-client
* stub.
*/
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING)
public interface MgmtDownloadArtifactClientResource extends MgmtDownloadArtifactRestApi {
}

View File

@@ -8,13 +8,13 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleRestAPI;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the SoftwareModule resource of the management API.
*
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/softwaremodules")
public interface SoftwareModuleResourceClient extends SoftwareModuleRestAPI {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE)
public interface MgmtDownloadClientResource extends MgmtDownloadRestApi {
}

View File

@@ -8,13 +8,13 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.RolloutRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the Rollout resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/rollouts")
public interface RolloutResourceClient extends RolloutRestApi {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING)
public interface MgmtRolloutClientResource extends MgmtRolloutRestApi {
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import feign.Param;
/**
* Client binding for the SoftwareModule resource of the management API.
*/
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING)
public interface MgmtSoftwareModuleClientResource extends MgmtSoftwareModuleRestApi {
@RequestMapping(method = RequestMethod.POST, value = "/{softwareModuleId}/artifacts")
ResponseEntity<MgmtArtifact> uploadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
@Param("file") final MultipartFile file,
@RequestParam(value = "filename", required = false) final String optionalFileName,
@RequestParam(value = "md5sum", required = false) final String md5Sum,
@RequestParam(value = "sha1sum", required = false) final String sha1Sum);
}

View File

@@ -8,13 +8,13 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleTypeRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the oftwareModuleType resource of the management API.
* Client binding for the SoftwareModuleType resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/softwaremoduletypes")
public interface SoftwareModuleTypeResourceClient extends SoftwareModuleTypeRestApi {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)
public interface MgmtSoftwareModuleTypeClientResource extends MgmtSoftwareModuleTypeRestApi {
}

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the {@link MgmtSystemRestApi}.
*
*/
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING)
public interface MgmtSystemClientResource extends MgmtSystemRestApi {
}

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemManagementRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the {@link MgmtSystemManagementRestApi}.
*
*/
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.SYSTEM_ADMIN_MAPPING)
public interface MgmtSystemManagementClientResource extends MgmtSystemManagementRestApi {
}

View File

@@ -8,13 +8,13 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.TargetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the Target resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targets")
public interface TargetResourceClient extends TargetRestApi {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)
public interface MgmtTargetClientResource extends MgmtTargetRestApi {
}

View File

@@ -8,13 +8,13 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.TargetTagRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the TargetTag resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targettags")
public interface TargetTagResourceClient extends TargetTagRestApi {
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING)
public interface MgmtTargetTagClientResource extends MgmtTargetTagRestApi {
}

View File

@@ -11,22 +11,23 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link DistributionSetRequestBodyPost}.
*
* @author Jonathan Knoblauch
*
* Builder pattern for building {@link MgmtDistributionSetRequestBodyPost}.
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class DistributionSetBuilder {
private String name;
private String version;
private String type;
private String description;
private final List<MgmtSoftwareModuleAssigment> modules = new ArrayList<>();
/**
* @param name
@@ -38,6 +39,13 @@ public class DistributionSetBuilder {
return this;
}
public DistributionSetBuilder moduleByID(final Long id) {
final MgmtSoftwareModuleAssigment softwareModuleAssigmentRest = new MgmtSoftwareModuleAssigment();
softwareModuleAssigmentRest.setId(id);
modules.add(softwareModuleAssigmentRest);
return this;
}
/**
* @param version
* the version of the distribution set
@@ -59,28 +67,38 @@ public class DistributionSetBuilder {
}
/**
* Builds a list with a single entry of
* {@link DistributionSetRequestBodyPost} which can directly be used to post
* on the RESTful-API.
*
* @return a single entry list of {@link DistributionSetRequestBodyPost}
* @param description
* the description
* @return the builder itself
*/
public List<DistributionSetRequestBodyPost> build() {
public DistributionSetBuilder description(final String description) {
this.description = description;
return this;
}
/**
* Builds a list with a single entry of
* {@link MgmtDistributionSetRequestBodyPost} which can directly be used to
* post on the RESTful-API.
*
* @return a single entry list of {@link MgmtDistributionSetRequestBodyPost}
*/
public List<MgmtDistributionSetRequestBodyPost> build() {
return Lists.newArrayList(doBuild(name));
}
/**
* Builds a list of multiple {@link DistributionSetRequestBodyPost} to
* Builds a list of multiple {@link MgmtDistributionSetRequestBodyPost} to
* create multiple distribution sets at once. An increasing number will be
* added to the name of the distribution set. The version and type will
* remain the same.
*
* @param count
* the amount of distribution sets body which should be created
* @return a list of {@link DistributionSetRequestBodyPost}
* @return a list of {@link MgmtDistributionSetRequestBodyPost}
*/
public List<DistributionSetRequestBodyPost> buildAsList(final int count) {
final ArrayList<DistributionSetRequestBodyPost> bodyList = Lists.newArrayList();
public List<MgmtDistributionSetRequestBodyPost> buildAsList(final int count) {
final ArrayList<MgmtDistributionSetRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index));
}
@@ -88,11 +106,13 @@ public class DistributionSetBuilder {
return bodyList;
}
private DistributionSetRequestBodyPost doBuild(final String prefixName) {
final DistributionSetRequestBodyPost body = new DistributionSetRequestBodyPost();
private MgmtDistributionSetRequestBodyPost doBuild(final String prefixName) {
final MgmtDistributionSetRequestBodyPost body = new MgmtDistributionSetRequestBodyPost();
body.setName(prefixName);
body.setVersion(version);
body.setType(type);
body.setDescription(description);
body.setModules(modules);
return body;
}

View File

@@ -11,24 +11,25 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeAssigmentRest;
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeAssigment;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link DistributionSetTypeRequestBodyPost}.
*
* @author Jonathan Knoblauch
* Builder pattern for building {@link MgmtDistributionSetTypeRequestBodyPost}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class DistributionSetTypeBuilder {
private String key;
private String name;
private final List<SoftwareModuleTypeAssigmentRest> mandatorymodules = Lists.newArrayList();
private final List<SoftwareModuleTypeAssigmentRest> optionalmodules = Lists.newArrayList();
private String description;
private final List<MgmtSoftwareModuleTypeAssigment> mandatorymodules = Lists.newArrayList();
private final List<MgmtSoftwareModuleTypeAssigment> optionalmodules = Lists.newArrayList();
/**
* @param key
@@ -50,6 +51,16 @@ public class DistributionSetTypeBuilder {
return this;
}
/**
* @param description
* the description
* @return the builder itself
*/
public DistributionSetTypeBuilder description(final String description) {
this.description = description;
return this;
}
/**
* @param softwareModuleTypeIds
* the IDs of the software module types which should be mandatory
@@ -58,7 +69,7 @@ public class DistributionSetTypeBuilder {
*/
public DistributionSetTypeBuilder mandatorymodules(final Long... softwareModuleTypeIds) {
for (final Long id : softwareModuleTypeIds) {
final SoftwareModuleTypeAssigmentRest softwareModuleTypeAssigmentRest = new SoftwareModuleTypeAssigmentRest();
final MgmtSoftwareModuleTypeAssigment softwareModuleTypeAssigmentRest = new MgmtSoftwareModuleTypeAssigment();
softwareModuleTypeAssigmentRest.setId(id);
this.mandatorymodules.add(softwareModuleTypeAssigmentRest);
}
@@ -74,7 +85,7 @@ public class DistributionSetTypeBuilder {
*/
public DistributionSetTypeBuilder optionalmodules(final Long... softwareModuleTypeIds) {
for (final Long id : softwareModuleTypeIds) {
final SoftwareModuleTypeAssigmentRest softwareModuleTypeAssigmentRest = new SoftwareModuleTypeAssigmentRest();
final MgmtSoftwareModuleTypeAssigment softwareModuleTypeAssigmentRest = new MgmtSoftwareModuleTypeAssigment();
softwareModuleTypeAssigmentRest.setId(id);
this.optionalmodules.add(softwareModuleTypeAssigmentRest);
}
@@ -83,28 +94,29 @@ public class DistributionSetTypeBuilder {
/**
* Builds a list with a single entry of
* {@link DistributionSetTypeRequestBodyPost} which can directly be used in
* the RESTful-API.
* {@link MgmtDistributionSetTypeRequestBodyPost} which can directly be used
* in the RESTful-API.
*
* @return a single entry list of {@link DistributionSetTypeRequestBodyPost}
* @return a single entry list of
* {@link MgmtDistributionSetTypeRequestBodyPost}
*/
public List<DistributionSetTypeRequestBodyPost> build() {
public List<MgmtDistributionSetTypeRequestBodyPost> build() {
return Lists.newArrayList(doBuild(name, key));
}
/**
* Builds a list of multiple {@link DistributionSetTypeRequestBodyPost} to
* create multiple distribution set types at once. An increasing number will
* be added to the name and key of the distribution set type. The optional
* and mandatory software module types will remain the same.
* Builds a list of multiple {@link MgmtDistributionSetTypeRequestBodyPost}
* to create multiple distribution set types at once. An increasing number
* will be added to the name and key of the distribution set type. The
* optional and mandatory software module types will remain the same.
*
* @param count
* the amount of distribution sets type body which should be
* created
* @return a list of {@link DistributionSetTypeRequestBodyPost}
* @return a list of {@link MgmtDistributionSetTypeRequestBodyPost}
*/
public List<DistributionSetTypeRequestBodyPost> buildAsList(final int count) {
final ArrayList<DistributionSetTypeRequestBodyPost> bodyList = Lists.newArrayList();
public List<MgmtDistributionSetTypeRequestBodyPost> buildAsList(final int count) {
final ArrayList<MgmtDistributionSetTypeRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index, key + index));
}
@@ -112,10 +124,11 @@ public class DistributionSetTypeBuilder {
}
private DistributionSetTypeRequestBodyPost doBuild(final String prefixName, final String prefixKey) {
final DistributionSetTypeRequestBodyPost body = new DistributionSetTypeRequestBodyPost();
private MgmtDistributionSetTypeRequestBodyPost doBuild(final String prefixName, final String prefixKey) {
final MgmtDistributionSetTypeRequestBodyPost body = new MgmtDistributionSetTypeRequestBodyPost();
body.setKey(prefixKey);
body.setName(prefixName);
body.setDescription(description);
body.setMandatorymodules(mandatorymodules);
body.setOptionalmodules(optionalmodules);
return body;

View File

@@ -8,17 +8,17 @@
*/
package org.eclipse.hawkbit.mgmt.client.resource.builder;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutCondition;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutCondition.Condition;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody;
/**
*
* Builder pattern for building {@link RolloutRestRequestBody}.
*
* @author Jonathan Knoblauch
* Builder pattern for building {@link MgmtRolloutRestRequestBody}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class RolloutBuilder {
private String name;
@@ -27,6 +27,7 @@ public class RolloutBuilder {
private long distributionSetId;
private String successThreshold;
private String errorThreshold;
private String description;
/**
* @param name
@@ -59,6 +60,16 @@ public class RolloutBuilder {
return this;
}
/**
* @param description
* the description
* @return the builder itself
*/
public RolloutBuilder description(final String description) {
this.description = description;
return this;
}
/**
* @param distributionSetId
* the ID of the distribution set to assign to the target in the
@@ -97,18 +108,19 @@ public class RolloutBuilder {
*
* @return the rest request body for creating a rollout
*/
public RolloutRestRequestBody build() {
public MgmtRolloutRestRequestBody build() {
return doBuild();
}
private RolloutRestRequestBody doBuild() {
final RolloutRestRequestBody body = new RolloutRestRequestBody();
private MgmtRolloutRestRequestBody doBuild() {
final MgmtRolloutRestRequestBody body = new MgmtRolloutRestRequestBody();
body.setName(name);
body.setAmountGroups(groupSize);
body.setTargetFilterQuery(targetFilterQuery);
body.setDistributionSetId(distributionSetId);
body.setSuccessCondition(new RolloutCondition(Condition.THRESHOLD, successThreshold));
body.setErrorCondition(new RolloutCondition(Condition.THRESHOLD, errorThreshold));
body.setDescription(description);
body.setSuccessCondition(new MgmtRolloutCondition(Condition.THRESHOLD, successThreshold));
body.setErrorCondition(new MgmtRolloutCondition(Condition.THRESHOLD, errorThreshold));
return body;
}

View File

@@ -11,15 +11,15 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleAssigmentRest;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment;
/**
*
* Builder pattern for building {@link SoftwareModuleAssigmentRest}.
*
* @author Jonathan Knoblauch
* Builder pattern for building {@link MgmtSoftwareModuleAssigment}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class SoftwareModuleAssigmentBuilder {
private final List<Long> ids;
@@ -39,15 +39,15 @@ public class SoftwareModuleAssigmentBuilder {
}
/**
* Builds a list with a single entry of {@link SoftwareModuleAssigmentRest}
* Builds a list with a single entry of {@link MgmtSoftwareModuleAssigment}
* which can directly be used in the RESTful-API.
*
* @return a single entry list of {@link SoftwareModuleAssigmentRest}
* @return a single entry list of {@link MgmtSoftwareModuleAssigment}
*/
public List<SoftwareModuleAssigmentRest> build() {
final List<SoftwareModuleAssigmentRest> softwareModuleAssigmentRestList = new ArrayList<>();
public List<MgmtSoftwareModuleAssigment> build() {
final List<MgmtSoftwareModuleAssigment> softwareModuleAssigmentRestList = new ArrayList<>();
for (final Long id : ids) {
final SoftwareModuleAssigmentRest softwareModuleAssigmentRest = new SoftwareModuleAssigmentRest();
final MgmtSoftwareModuleAssigment softwareModuleAssigmentRest = new MgmtSoftwareModuleAssigment();
softwareModuleAssigmentRest.setId(id);
softwareModuleAssigmentRestList.add(softwareModuleAssigmentRest);
}

View File

@@ -11,23 +11,25 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link SoftwareModuleRequestBodyPost}.
*
* @author Jonathan Knoblauch
* Builder pattern for building {@link MgmtSoftwareModuleRequestBodyPost}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class SoftwareModuleBuilder {
private String name;
private String version;
private String type;
private String vendor;
private String description;
/**
* @param name
@@ -61,28 +63,48 @@ public class SoftwareModuleBuilder {
}
/**
* Builds a list with a single entry of
* {@link SoftwareModuleRequestBodyPost} which can directly be used in the
* RESTful-API.
*
* @return a single entry list of {@link SoftwareModuleRequestBodyPost}
* @param vendor
* the vendor
* @return the builder itself
*/
public List<SoftwareModuleRequestBodyPost> build() {
public SoftwareModuleBuilder vendor(final String vendor) {
this.vendor = vendor;
return this;
}
/**
* @param description
* the description
* @return the builder itself
*/
public SoftwareModuleBuilder description(final String description) {
this.description = description;
return this;
}
/**
* Builds a list with a single entry of
* {@link MgmtSoftwareModuleRequestBodyPost} which can directly be used in
* the RESTful-API.
*
* @return a single entry list of {@link MgmtSoftwareModuleRequestBodyPost}
*/
public List<MgmtSoftwareModuleRequestBodyPost> build() {
return Lists.newArrayList(doBuild(name));
}
/**
* Builds a list of multiple {@link SoftwareModuleRequestBodyPost} to create
* multiple software module at once. An increasing number will be added to
* the name of the software module. The version and type will remain the
* same.
* Builds a list of multiple {@link MgmtSoftwareModuleRequestBodyPost} to
* create multiple software module at once. An increasing number will be
* added to the name of the software module. The version and type will
* remain the same.
*
* @param count
* the amount of software module body which should be created
* @return a list of {@link DistributionSetTypeRequestBodyPost}
* @return a list of {@link MgmtDistributionSetTypeRequestBodyPost}
*/
public List<SoftwareModuleRequestBodyPost> buildAsList(final int count) {
final ArrayList<SoftwareModuleRequestBodyPost> bodyList = Lists.newArrayList();
public List<MgmtSoftwareModuleRequestBodyPost> buildAsList(final int count) {
final ArrayList<MgmtSoftwareModuleRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index));
}
@@ -90,11 +112,13 @@ public class SoftwareModuleBuilder {
return bodyList;
}
private SoftwareModuleRequestBodyPost doBuild(final String prefixName) {
final SoftwareModuleRequestBodyPost body = new SoftwareModuleRequestBodyPost();
private MgmtSoftwareModuleRequestBodyPost doBuild(final String prefixName) {
final MgmtSoftwareModuleRequestBodyPost body = new MgmtSoftwareModuleRequestBodyPost();
body.setName(prefixName);
body.setVersion(version);
body.setType(type);
body.setVendor(vendor);
body.setDescription(description);
return body;
}

View File

@@ -11,18 +11,18 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link SoftwareModuleRequestBodyPost}.
*
* @author Jonathan Knoblauch
* Builder pattern for building {@link MgmtSoftwareModuleRequestBodyPost}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class SoftwareModuleTypeBuilder {
private String key;
@@ -62,35 +62,36 @@ public class SoftwareModuleTypeBuilder {
/**
* Builds a list with a single entry of
* {@link SoftwareModuleTypeRequestBodyPost} which can directly be used in
* the RESTful-API.
* {@link MgmtSoftwareModuleTypeRequestBodyPost} which can directly be used
* in the RESTful-API.
*
* @return a single entry list of {@link SoftwareModuleTypeRequestBodyPost}
* @return a single entry list of
* {@link MgmtSoftwareModuleTypeRequestBodyPost}
*/
public List<SoftwareModuleTypeRequestBodyPost> build() {
public List<MgmtSoftwareModuleTypeRequestBodyPost> build() {
return Lists.newArrayList(doBuild(key, name));
}
/**
* Builds a list of multiple {@link SoftwareModuleTypeRequestBodyPost} to
* create multiple software module types at once. An increasing number will
* be added to the name and key of the software module type.
* Builds a list of multiple {@link MgmtSoftwareModuleTypeRequestBodyPost}
* to create multiple software module types at once. An increasing number
* will be added to the name and key of the software module type.
*
* @param count
* the amount of software module type bodies which should be
* created
* @return a list of {@link SoftwareModuleTypeRequestBodyPost}
* @return a list of {@link MgmtSoftwareModuleTypeRequestBodyPost}
*/
public List<SoftwareModuleTypeRequestBodyPost> buildAsList(final int count) {
final ArrayList<SoftwareModuleTypeRequestBodyPost> bodyList = Lists.newArrayList();
public List<MgmtSoftwareModuleTypeRequestBodyPost> buildAsList(final int count) {
final ArrayList<MgmtSoftwareModuleTypeRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(key + index, name + index));
}
return bodyList;
}
private SoftwareModuleTypeRequestBodyPost doBuild(final String prefixKey, final String prefixName) {
final SoftwareModuleTypeRequestBodyPost body = new SoftwareModuleTypeRequestBodyPost();
private MgmtSoftwareModuleTypeRequestBodyPost doBuild(final String prefixKey, final String prefixName) {
final MgmtSoftwareModuleTypeRequestBodyPost body = new MgmtSoftwareModuleTypeRequestBodyPost();
body.setKey(prefixKey);
body.setName(prefixName);
body.setDescription(description);

View File

@@ -11,16 +11,16 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
import com.google.common.collect.Lists;
/**
* Builder pattern for building {@link TagRequestBodyPut}.
*
* @author Jonathan Knoblauch
* Builder pattern for building {@link MgmtTagRequestBodyPut}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class TagBuilder {
private String name;
@@ -58,26 +58,26 @@ public class TagBuilder {
}
/**
* Builds a list with a single entry of {@link TagRequestBodyPut} which can
* directly be used in the RESTful-API.
* Builds a list with a single entry of {@link MgmtTagRequestBodyPut} which
* can directly be used in the RESTful-API.
*
* @return a single entry list of {@link TagRequestBodyPut}
* @return a single entry list of {@link MgmtTagRequestBodyPut}
*/
public List<TagRequestBodyPut> build() {
public List<MgmtTagRequestBodyPut> build() {
return Lists.newArrayList(doBuild(name));
}
/**
* Builds a list of multiple {@link TagRequestBodyPut} to create multiple
* tags at once. An increasing number will be added to the name of the tag.
* The color and description will remain the same.
* Builds a list of multiple {@link MgmtTagRequestBodyPut} to create
* multiple tags at once. An increasing number will be added to the name of
* the tag. The color and description will remain the same.
*
* @param count
* the amount of distribution sets body which should be created
* @return a list of {@link TagRequestBodyPut}
* @return a list of {@link MgmtTagRequestBodyPut}
*/
public List<TagRequestBodyPut> buildAsList(final int count) {
final ArrayList<TagRequestBodyPut> bodyList = Lists.newArrayList();
public List<MgmtTagRequestBodyPut> buildAsList(final int count) {
final ArrayList<MgmtTagRequestBodyPut> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index));
}
@@ -85,8 +85,8 @@ public class TagBuilder {
return bodyList;
}
private TagRequestBodyPut doBuild(final String prefixName) {
final TagRequestBodyPut body = new TagRequestBodyPut();
private MgmtTagRequestBodyPut doBuild(final String prefixName) {
final MgmtTagRequestBodyPut body = new MgmtTagRequestBodyPut();
body.setName(prefixName);
body.setDescription(description);
body.setColour(color);

View File

@@ -11,18 +11,18 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link TargetRequestBody}.
*
* @author Jonathan Knoblauch
* Builder pattern for building {@link MgmtTargetRequestBody}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class TargetBuilder {
private String controllerId;
@@ -60,35 +60,35 @@ public class TargetBuilder {
}
/**
* Builds a list with a single entry of {@link TargetRequestBody} which can
* directly be used in the RESTful-API.
* Builds a list with a single entry of {@link MgmtTargetRequestBody} which
* can directly be used in the RESTful-API.
*
* @return a single entry list of {@link TargetRequestBody}
* @return a single entry list of {@link MgmtTargetRequestBody}
*/
public List<TargetRequestBody> build() {
public List<MgmtTargetRequestBody> build() {
return Lists.newArrayList(doBuild(controllerId));
}
/**
* Builds a list of multiple {@link TargetRequestBody} to create multiple
* targets at once. An increasing number will be added to the controllerId
* of the target. The name and description will remain.
* Builds a list of multiple {@link MgmtTargetRequestBody} to create
* multiple targets at once. An increasing number will be added to the
* controllerId of the target. The name and description will remain.
*
* @param count
* the amount of software module type bodies which should be
* created
* @return a list of {@link SoftwareModuleTypeRequestBodyPost}
* @return a list of {@link MgmtSoftwareModuleTypeRequestBodyPost}
*/
public List<TargetRequestBody> buildAsList(final int count) {
final ArrayList<TargetRequestBody> bodyList = Lists.newArrayList();
public List<MgmtTargetRequestBody> buildAsList(final int count) {
final ArrayList<MgmtTargetRequestBody> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(controllerId + index));
}
return bodyList;
}
private TargetRequestBody doBuild(final String prefixControllerId) {
final TargetRequestBody body = new TargetRequestBody();
private MgmtTargetRequestBody doBuild(final String prefixControllerId) {
final MgmtTargetRequestBody body = new MgmtTargetRequestBody();
body.setControllerId(prefixControllerId);
body.setName(name);
body.setDescription(description);

View File

@@ -0,0 +1,3 @@
/target/
/bin/
/.apt_generated/

View File

@@ -1,6 +1,6 @@
# HawkBit management API example
# Eclipse.IoT hawkBit - Example Management Feign Client
Example client that shows how to efficiently use the hawkBit management API.
Example Spring Boot client that shows how to efficiently use the hawkBit Example Management Feign Client and the hawkBit Management API.
Powered by [Feign](https://github.com/Netflix/feign).
@@ -10,13 +10,13 @@ Run getting started example
$ java -jar hawkbit-mgmt-api-client-#version#.jar
$ java -jar hawkbit-example-mgmt-simulator-#version#.jar
Run create and start rollout example
$ java -jar hawkbit-mgmt-api-client-#version#.jar --createrollout
$ java -jar hawkbit-example-mgmt-simulator-#version#.jar --createrollout
## This example shows
@@ -28,7 +28,7 @@ In getting started example:
* creating software modules
* assigning software modules to distribution sets
In rollout mode:
In create rollout example:
* creating software modules type
* creating distribution set type
* creating distribution sets
@@ -36,4 +36,3 @@ In rollout mode:
* assigning software modules to distribution sets
* creating a rollout
* starting a rollout

View File

@@ -17,8 +17,8 @@
<version>0.2.0-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<artifactId>hawkbit-mgmt-api-client</artifactId>
<name>hawkBit Management API example client</name>
<artifactId>hawkbit-example-mgmt-simulator</artifactId>
<name>hawkBit-example :: Management feign client simulator</name>
<build>
<plugins>
@@ -57,14 +57,20 @@
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-rest-api</artifactId>
<artifactId>hawkbit-example-mgmt-feign-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<!-- need to overwrite for the interface inheritance feature of feign-core -->
<version>8.14.2</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<artifactId>hibernate-validator</artifactId>
@@ -82,11 +88,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0-rc2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>

View File

@@ -8,22 +8,28 @@
*/
package org.eclipse.hawkbit.mgmt.client;
import org.eclipse.hawkbit.feign.core.client.FeignClientConfiguration;
import org.eclipse.hawkbit.mgmt.client.scenarios.CreateStartedRolloutExample;
import org.eclipse.hawkbit.mgmt.client.scenarios.GettingStartedDefaultScenario;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import feign.Contract;
import feign.auth.BasicAuthRequestInterceptor;
@SpringBootApplication
@EnableFeignClients
@EnableConfigurationProperties(ClientConfigurationProperties.class)
@Configuration
@AutoConfigureAfter(FeignClientConfiguration.class)
@Import(FeignClientConfiguration.class)
public class Application implements CommandLineRunner {
@Autowired
@@ -57,13 +63,13 @@ public class Application implements CommandLineRunner {
}
@Bean
public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() {
return new ApplicationJsonRequestHeaderInterceptor();
public GettingStartedDefaultScenario gettingStartedDefaultScenario() {
return new GettingStartedDefaultScenario();
}
@Bean
public Contract feignContract() {
return new IgnoreMultipleConsumersProducersSpringMvcContract();
public CreateStartedRolloutExample createStartedRolloutExample() {
return new CreateStartedRolloutExample();
}
private boolean containsArg(final String containsArg, final String... args) {

View File

@@ -8,12 +8,14 @@
*/
package org.eclipse.hawkbit.mgmt.client.scenarios;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.RolloutResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.TargetResourceClient;
import java.util.List;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetTypeClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtRolloutClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleTypeClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtTargetClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.RolloutBuilder;
@@ -21,43 +23,41 @@ import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentB
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.TargetBuilder;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModulesRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Example for creating and starting a Rollout.
*
*/
@Component
public class CreateStartedRolloutExample {
/* known software module type name and key */
private static final String SM_MODULE_TYPE = "firmware";
/* known distribution set type name and key */
private static final String DS_MODULE_TYPE = "firmware";
private static final String DS_MODULE_TYPE = SM_MODULE_TYPE;
@Autowired
private DistributionSetResourceClient distributionSetResource;
private MgmtDistributionSetClientResource distributionSetResource;
@Autowired
private SoftwareModuleResourceClient softwareModuleResource;
private MgmtSoftwareModuleClientResource softwareModuleResource;
@Autowired
private TargetResourceClient targetResource;
private MgmtTargetClientResource targetResource;
@Autowired
private RolloutResourceClient rolloutResource;
private MgmtRolloutClientResource rolloutResource;
@Autowired
private DistributionSetTypeResourceClient distributionSetTypeResource;
private MgmtDistributionSetTypeClientResource distributionSetTypeResource;
@Autowired
private SoftwareModuleTypeResourceClient softwareModuleTypeResource;
private MgmtSoftwareModuleTypeClientResource softwareModuleTypeResource;
/**
* Run the Rollout scenario.
@@ -65,8 +65,9 @@ public class CreateStartedRolloutExample {
public void run() {
// create three SoftwareModuleTypes
final SoftwareModuleTypesRest createdSoftwareModuleTypes = softwareModuleTypeResource.createSoftwareModuleTypes(
new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE).maxAssignments(1).build())
final List<MgmtSoftwareModuleType> createdSoftwareModuleTypes = softwareModuleTypeResource
.createSoftwareModuleTypes(new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE)
.maxAssignments(1).build())
.getBody();
// create one DistributionSetType
@@ -75,12 +76,12 @@ public class CreateStartedRolloutExample {
.getBody();
// create one DistributionSet
final DistributionSetsRest distributionSetsRest = distributionSetResource.createDistributionSets(
final List<MgmtDistributionSet> distributionSetsRest = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name("rollout-example").version("1.0.0").type(DS_MODULE_TYPE).build())
.getBody();
// create three SoftwareModules
final SoftwareModulesRest softwareModulesRest = softwareModuleResource
final List<MgmtSoftwareModule> softwareModulesRest = softwareModuleResource
.createSoftwareModules(
new SoftwareModuleBuilder().name("firmware").version("1.0.0").type(SM_MODULE_TYPE).build())
.getBody();
@@ -94,7 +95,7 @@ public class CreateStartedRolloutExample {
.description("Targets used for rollout example").buildAsList(10));
// create a Rollout
final RolloutResponseBody rolloutResponseBody = rolloutResource
final MgmtRolloutResponseBody rolloutResponseBody = rolloutResource
.create(new RolloutBuilder().name("MyRollout").groupSize(2).targetFilterQuery("name==00-FF-AA-0*")
.distributionSetId(distributionSetsRest.get(0).getDsId()).successThreshold("80")
.errorThreshold("50").build())

View File

@@ -8,29 +8,29 @@
*/
package org.eclipse.hawkbit.mgmt.client.scenarios;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleTypeResourceClient;
import java.util.List;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetTypeClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleTypeClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModulesRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
*
* Default getting started scenario.
*
*/
@Component
public class GettingStartedDefaultScenario {
private static final Logger LOGGER = LoggerFactory.getLogger(GettingStartedDefaultScenario.class);
@@ -39,25 +39,25 @@ public class GettingStartedDefaultScenario {
private static final String SM_MODULE_TYPE = "gettingstarted";
/* known distribution set type name and key */
private static final String DS_MODULE_TYPE = "gettingstarted";
private static final String DS_MODULE_TYPE = SM_MODULE_TYPE;
/* known distribution name of this getting started example */
private static final String SM_EXAMPLE_NAME = "gettingstarted-example";
/* known distribution name of this getting started example */
private static final String DS_EXAMPLE_NAME = "gettingstarted-example";
private static final String DS_EXAMPLE_NAME = SM_EXAMPLE_NAME;
@Autowired
private DistributionSetResourceClient distributionSetResource;
private MgmtDistributionSetClientResource distributionSetResource;
@Autowired
private DistributionSetTypeResourceClient distributionSetTypeResource;
private MgmtDistributionSetTypeClientResource distributionSetTypeResource;
@Autowired
private SoftwareModuleResourceClient softwareModuleResource;
private MgmtSoftwareModuleClientResource softwareModuleResource;
@Autowired
private SoftwareModuleTypeResourceClient softwareModuleTypeResource;
private MgmtSoftwareModuleTypeClientResource softwareModuleTypeResource;
/**
* Run the default getting started scenario.
@@ -68,8 +68,9 @@ public class GettingStartedDefaultScenario {
// create one SoftwareModuleTypes
LOGGER.info("Creating software module type {}", SM_MODULE_TYPE);
final SoftwareModuleTypesRest createdSoftwareModuleTypes = softwareModuleTypeResource.createSoftwareModuleTypes(
new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE).maxAssignments(1).build())
final List<MgmtSoftwareModuleType> createdSoftwareModuleTypes = softwareModuleTypeResource
.createSoftwareModuleTypes(new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE)
.maxAssignments(1).build())
.getBody();
// create one DistributionSetType
@@ -83,17 +84,17 @@ public class GettingStartedDefaultScenario {
final String dsVersion3 = "2.1.0";
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion1);
final DistributionSetsRest distributionSetsRest1 = distributionSetResource.createDistributionSets(
final List<MgmtDistributionSet> distributionSetsRest1 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion1).type(DS_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion2);
final DistributionSetsRest distributionSetsRest2 = distributionSetResource.createDistributionSets(
final List<MgmtDistributionSet> distributionSetsRest2 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion2).type(DS_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion3);
final DistributionSetsRest distributionSetsRest3 = distributionSetResource.createDistributionSets(
final List<MgmtDistributionSet> distributionSetsRest3 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion3).type(DS_MODULE_TYPE).build())
.getBody();
@@ -103,15 +104,15 @@ public class GettingStartedDefaultScenario {
final String swVersion3 = "3";
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion1);
final SoftwareModulesRest softwareModulesRest1 = softwareModuleResource.createSoftwareModules(
final List<MgmtSoftwareModule> softwareModulesRest1 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion1).type(SM_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion2);
final SoftwareModulesRest softwareModulesRest2 = softwareModuleResource.createSoftwareModules(
final List<MgmtSoftwareModule> softwareModulesRest2 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion2).type(SM_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion3);
final SoftwareModulesRest softwareModulesRest3 = softwareModuleResource.createSoftwareModules(
final List<MgmtSoftwareModule> softwareModulesRest3 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion3).type(SM_MODULE_TYPE).build())
.getBody();

View File

@@ -8,8 +8,7 @@
http://www.eclipse.org/legal/epl-v10.html
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -19,13 +18,45 @@
</parent>
<artifactId>hawkbit-examples-parent</artifactId>
<name>hawkBit :: Examples Parent</name>
<name>hawkBit-example :: Parent</name>
<packaging>pom</packaging>
<modules>
<module>hawkbit-device-simulator</module>
<module>hawkbit-example-app</module>
<module>hawkbit-mgmt-api-client</module>
</modules>
<module>hawkbit-example-core-feign-client</module>
<module>hawkbit-example-ddi-feign-client</module>
<module>hawkbit-example-mgmt-feign-client</module>
<module>hawkbit-example-mgmt-simulator</module>
</modules>
<properties>
<feign.version>8.14.2</feign.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<!-- need to overwrite for the interface inheritance feature of feign-core -->
<!-- <version>8.16.0</version> -->
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<!-- need to overwrite for the interface inheritance feature of feign-core -->
<!-- <version>8.16.0</version> -->
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>${feign.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -8,11 +8,14 @@
*/
package org.eclipse.hawkbit.artifact.repository;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -38,10 +41,7 @@ import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSFile;
/**
* The file management which looks up all the file in the filestore.
*
*
*
* The file management which looks up all the file in the file tore.
*
*/
public class ArtifactStore implements ArtifactRepository {
@@ -60,7 +60,7 @@ public class ArtifactStore implements ArtifactRepository {
private static final String MD5 = "md5";
/**
* The mongoDB field which holds the SHA1 hash, stored in the metadata
* The mongoDB field which holds the SHA1 hash, stored in the meta data
* object.
*/
private static final String SHA1 = "sha1";
@@ -75,11 +75,10 @@ public class ArtifactStore implements ArtifactRepository {
/**
* Retrieves a {@link GridFSDBFile} from the store by it's SHA1 hash.
*
* @param tenant
* the tenant to retrieve the artifacts from, ignore case.
* @param sha1Hash
* the sha1-hash of the file to lookup.
* @return The gridfs file object or {@code null} if no file exists.
*
* @return The DbArtifact object or {@code null} if no file exists.
*/
@Override
public DbArtifact getArtifactBySha1(final String sha1Hash) {
@@ -126,7 +125,11 @@ public class ArtifactStore implements ArtifactRepository {
LOGGER.debug("storing file {} of content {}", filename, contentType);
tempFile = File.createTempFile("uploadFile", null);
try (final FileOutputStream os = new FileOutputStream(tempFile)) {
return store(content, contentType, os, tempFile, hash);
try (BufferedOutputStream bos = new BufferedOutputStream(os)) {
try (BufferedInputStream bis = new BufferedInputStream(content)) {
return store(content, contentType, bos, tempFile, hash);
}
}
}
} catch (final IOException | MongoException e1) {
throw new ArtifactStoreException(e1.getMessage(), e1);
@@ -166,7 +169,7 @@ public class ArtifactStore implements ArtifactRepository {
}
private DbArtifact store(final InputStream content, final String contentType, final FileOutputStream os,
private DbArtifact store(final InputStream content, final String contentType, final OutputStream os,
final File tempFile, final DbArtifactHash hash) {
final GridFsArtifact storedArtifact;
try {
@@ -189,7 +192,8 @@ public class ArtifactStore implements ArtifactRepository {
throw new ArtifactStoreException(e.getMessage(), e);
}
if (hash != null && hash.getMd5() != null && !storedArtifact.getHashes().getMd5().equals(hash.getMd5())) {
if (hash != null && hash.getMd5() != null
&& !storedArtifact.getHashes().getMd5().equalsIgnoreCase(hash.getMd5())) {
throw new HashNotMatchException("The given md5 hash " + hash.getMd5()
+ " not matching the calculated md5 hash " + storedArtifact.getHashes().getMd5(),
HashNotMatchException.MD5);
@@ -199,14 +203,14 @@ public class ArtifactStore implements ArtifactRepository {
}
private static String computeSHA1Hash(final InputStream stream, final FileOutputStream os,
final String providedSHA1Sum) throws NoSuchAlgorithmException, IOException {
private static String computeSHA1Hash(final InputStream stream, final OutputStream os, final String providedSHA1Sum)
throws NoSuchAlgorithmException, IOException {
String sha1Hash;
// compute digest
final MessageDigest md = MessageDigest.getInstance("SHA-1");
final DigestOutputStream dos = new DigestOutputStream(os, md);
ByteStreams.copy(stream, dos);
dos.close();
try (final DigestOutputStream dos = new DigestOutputStream(os, md)) {
ByteStreams.copy(stream, dos);
}
sha1Hash = BaseEncoding.base16().lowerCase().encode(md.digest());
if (providedSHA1Sum != null && !providedSHA1Sum.equalsIgnoreCase(sha1Hash)) {
throw new HashNotMatchException(
@@ -226,8 +230,7 @@ public class ArtifactStore implements ArtifactRepository {
* @return a paged list of artifacts mapped from the given dbFiles
*/
private List<DbArtifact> map(final List<GridFSDBFile> dbFiles) {
final List<DbArtifact> collect = dbFiles.stream().map(dbFile -> map(dbFile)).collect(Collectors.toList());
return collect;
return dbFiles.stream().map(dbFile -> map(dbFile)).collect(Collectors.toList());
}
/**
@@ -238,7 +241,7 @@ public class ArtifactStore implements ArtifactRepository {
* the tenant to retrieve the artifacts from, ignore case.
* @param sha1Hashes
* the sha1-hashes of the files to lookup.
* @return list of artfiacts
* @return list of artifacts
*/
@Override
public List<DbArtifact> getArtifactsBySha1(final List<String> sha1Hashes) {

View File

@@ -71,6 +71,8 @@ public class MongoConfiguration extends AbstractMongoConfiguration {
@Override
@Bean
@ConditionalOnMissingBean
// Closed by pre-destroy
@SuppressWarnings({ "squid:S2095" })
public Mongo mongo() throws UnknownHostException {
final MongoClientURI uri = new MongoClientURI(properties.getUri(), createBuilderOutOfOptions(options));

View File

@@ -64,7 +64,13 @@
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-rest-resource</artifactId>
<artifactId>hawkbit-ddi-resource</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-mgmt-resource</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>

View File

@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.autoconfigure.security;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
@@ -27,14 +26,15 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.rest.resource.RestConstants;
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.DosFilter;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateAnonymousDownloadFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
@@ -83,6 +83,8 @@ import org.vaadin.spring.security.web.VaadinRedirectStrategy;
import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler;
import com.google.common.collect.Lists;
/**
* All configurations related to SP authentication and authorization layer.
*
@@ -147,6 +149,12 @@ public class SecurityManagedConfiguration {
gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
final HttpControllerPreAuthenticateAnonymousDownloadFilter controllerAnonymousDownloadFilter = new HttpControllerPreAuthenticateAnonymousDownloadFilter(
tenantConfigurationManagement, tenantAware, systemSecurityContext);
controllerAnonymousDownloadFilter.setAuthenticationManager(authenticationManager());
controllerAnonymousDownloadFilter.setCheckForPrincipalChanges(true);
controllerAnonymousDownloadFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
HttpSecurity httpSec = http.csrf().disable().headers()
.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY)).contentTypeOptions()
.xssProtection().httpStrictTransportSecurity().and();
@@ -159,15 +167,17 @@ public class SecurityManagedConfiguration {
LOG.info(
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous", Collections.singletonList(
new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
"controllerAnonymousFilter", "anonymous",
Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS),
new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE)));
anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and()
.securityContext().disable().anonymous().authenticationFilter(anoymousFilter);
} else {
httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
.addFilter(gatewaySecurityTokenFilter).antMatcher("/*/controller/**").anonymous().disable()
.authorizeRequests().anyRequest().authenticated().and().exceptionHandling()
.addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter)
.antMatcher("/*/controller/**").anonymous().disable().authorizeRequests().anyRequest()
.authenticated().and().exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response
.setStatus(HttpStatus.UNAUTHORIZED.value()))
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
@@ -282,8 +292,9 @@ public class SecurityManagedConfiguration {
new AuthenticationSuccessTenantMetadataCreationFilter(tenantAware, systemManagement),
RequestHeaderAuthenticationFilter.class)
.authorizeRequests().anyRequest().authenticated()
.antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN).antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/**")
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN)
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/**")
.hasAnyAuthority(SpPermission.SYSTEM_DIAG);
}
}

View File

@@ -9,6 +9,9 @@
package org.eclipse.hawkbit.autoconfigure.ui;
import org.eclipse.hawkbit.DistributedResourceBundleMessageSource;
import org.eclipse.hawkbit.ui.HawkbitEventProvider;
import org.eclipse.hawkbit.ui.UIEventProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.vaadin.spring.annotation.EnableVaadinExtensions;
@@ -17,9 +20,6 @@ import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
/**
* The hawkbit-ui autoconfiguration.
*
*
*
*/
@Configuration
@EnableVaadinSecurity
@@ -37,4 +37,15 @@ public class UIAutoConfiguration {
return new DistributedResourceBundleMessageSource();
}
/**
* A event provider bean which hold the supported events for the UI.
*
* @return the provider bean
*/
@Bean
@ConditionalOnMissingBean
public UIEventProvider eventProvider() {
return new HawkbitEventProvider();
}
}

View File

@@ -8,21 +8,19 @@
*/
package org.eclipse.hawkbit.autoconfigure.web;
import org.eclipse.hawkbit.controller.EnableDirectDeviceApi;
import org.eclipse.hawkbit.rest.resource.EnableRestResources;
import org.eclipse.hawkbit.ddi.EnableDdiApi;
import org.eclipse.hawkbit.mgmt.EnableMgmtApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Auto-Configuration for enabling the REST-Resources.
*
*
*
*/
@Configuration
@ConditionalOnClass({ EnableDirectDeviceApi.class, EnableRestResources.class })
@Import({ EnableDirectDeviceApi.class, EnableRestResources.class })
@ConditionalOnClass({ EnableDdiApi.class, EnableMgmtApi.class })
@Import({ EnableDdiApi.class, EnableMgmtApi.class })
public class ResourceControllerAutoConfiguration {
}

View File

@@ -42,6 +42,6 @@ hawkbit.controller.minPollingTime=00:00:30
# Configuration for RabbitMQ integration
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter_ttl
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver

3
hawkbit-core/README.md Normal file
View File

@@ -0,0 +1,3 @@
# hawkBit Core
Various internal interfaces and utility classes.

View File

@@ -31,7 +31,7 @@ public class ControllerPollProperties {
* Maximum polling time that can be configured by a tenant in HH:MM:SS
* notation.
*/
private String maxPollingTime = "23:59:00";
private String maxPollingTime = "23:59:59";
/**
* Minimum polling time that can be configured by a tenant in HH:MM:SS

Some files were not shown because too many files have changed in this diff Show More