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.support has changed to hawkbit.server.ui.links.support
- hawkbit.server.email.request.account has changed to hawkbit.server.ui.links.requestAccount - 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 - 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). * 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. * 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 # 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 #### 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 $ java -jar ./examples/hawkbit-device-simulator/target/hawkbit-device-simulator-#version#.jar
``` ```
#### Generate Getting Started data #### 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 # 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: * The master branch contains future development towards 0.2. We are currently focusing on:
* Rollout Management for large scale rollouts. * Rollout Management for large scale rollouts.
* Clustering capabilities for the update server. * 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. * And of course tons of usability improvements and bug fixes.
# Modules # Modules
`hawkbit-core` : core elements. * `examples` : hawkBit examples
`hawkbit-security-core` : core security elements. * `hawkbit-artifact-repository-mongo` : Artifact repository implementation to mongoDB.
`hawkbit-security-integration` : security integration elements to integrate security into hawkbit. * `hawkbit-autoconfigure` : Spring-boot auto-configuration.
`hawkbit-artifact-repository-mongo` : artifact repository implementation to mongoDB. * `hawkbit-cache-redis` : Spring cache manager configuration and implementation with redis, distributed cache and distributed events.
`hawkbit-autoconfigure` : spring-boot auto-configuration. * `hawkbit-core` : Core elements for internal interfaces and utility classes.
`hawkbit-dmf-api` : API for the Device Management Integration. * `hawkbit-ddi-api` : The hawkBit DDI API.
`hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API. * `hawkbit-ddi-dl-api` : The hawkBit DDI Download API.
`hawkbit-repository` : repository implemenation based on SQL for all meta-data. * `hawkbit-ddi-resource` : Implementation of the hawkBit DDI API
`hawkbit-http-security` : implementation for security filters for HTTP. * `hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API.
`hawkbit-rest-api` : API classes for the REST Management API. * `hawkbit-dmf-api` : API for the Device Management Integration.
`hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API. * `hawkbit-http-security` : Implementation for security filters for HTTP.
`hawkbit-ui` : Vaadin UI. * `hawkbit-mgmt-api` : The hawkBit Management API
`hawkbit-cache-redis` : spring cache manager configuration and implementation with redis, distributed cache and distributed events. * `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 # 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. 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 java -jar examples/hawkbit-device-simulator/target/hawkbit-device-simulator-*-SNAPSHOT.jar
``` ```
@@ -11,6 +11,11 @@ Or:
run org.eclipse.hawkbit.simulator.DeviceSimulator run org.eclipse.hawkbit.simulator.DeviceSimulator
``` ```
## Deploy to cloud foundry environment
- Go to ```target``` subfolder.
- Run ```cf push```
## Notes ## Notes
The simulator has user authentication enabled in **cloud profile**. Default credentials: 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/generateScreenshot.png)
![](src/main/images/updateProcessScreenshot.png) ![](src/main/images/updateProcessScreenshot.png)
![](src/main/images/updateResultOverviewScreenshot.png) ![](src/main/images/updateResultOverviewScreenshot.png)
@@ -54,12 +59,12 @@ Example: for 20 simulated devices (default)
http://localhost:8083/start 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 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 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. Copyright (c) 2015 Bosch Software Innovations GmbH and others.
@@ -9,7 +8,8 @@
http://www.eclipse.org/legal/epl-v10.html 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"> xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
@@ -19,7 +19,7 @@
</parent> </parent>
<artifactId>hawkbit-device-simulator</artifactId> <artifactId>hawkbit-device-simulator</artifactId>
<name>hawkBit :: Device Simulator</name> <name>hawkBit-example :: Device Simulator</name>
<description>Device Management Federation API based simulator</description> <description>Device Management Federation API based simulator</description>
<build> <build>
@@ -42,6 +42,19 @@
</executions> </executions>
</plugin> </plugin>
</plugins> </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> </build>
<dependencies> <dependencies>
@@ -69,16 +82,26 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- Log4j API and Core implementation required for binding -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId> <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>
<dependency> <dependency>
<groupId>com.vaadin</groupId> <groupId>com.vaadin</groupId>
@@ -120,13 +143,17 @@
<artifactId>spring-boot-configuration-processor</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies> </dependencies>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.vaadin</groupId> <groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId> <artifactId>vaadin-bom</artifactId>
<version>7.6.3</version> <version>${vaadin.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>

View File

@@ -8,6 +8,8 @@
*/ */
package org.eclipse.hawkbit.simulator; package org.eclipse.hawkbit.simulator;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
/** /**
* The bean of a simulated device which can be stored in the * The bean of a simulated device which can be stored in the
* {@link DeviceSimulatorRepository} or shown in the UI. * {@link DeviceSimulatorRepository} or shown in the UI.
@@ -22,16 +24,15 @@ public abstract class AbstractSimulatedDevice {
private Status status; private Status status;
private double progress; private double progress;
private String swversion = "unknown"; 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 Protocol protocol = Protocol.DMF_AMQP;
private String targetSecurityToken;
private int nextPollCounterSec; private int nextPollCounterSec;
/** /**
* Enum definition of the protocol to be used for the simulated device. * Enum definition of the protocol to be used for the simulated device.
* *
* @author Michael Hirsch
*
*/ */
public enum Protocol { public enum Protocol {
/** /**
@@ -69,24 +70,6 @@ public abstract class AbstractSimulatedDevice {
ERROR; 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. * empty constructor.
*/ */
@@ -158,12 +141,12 @@ public abstract class AbstractSimulatedDevice {
this.swversion = swversion; this.swversion = swversion;
} }
public ResponseStatus getResponseStatus() { public UpdateStatus getUpdateStatus() {
return responseStatus; return updateStatus;
} }
public void setResponseStatus(final ResponseStatus responseStatus) { public void setUpdateStatus(final UpdateStatus updateStatus) {
this.responseStatus = responseStatus; this.updateStatus = updateStatus;
} }
public Protocol getProtocol() { public Protocol getProtocol() {
@@ -177,4 +160,13 @@ public abstract class AbstractSimulatedDevice {
public void setNextPollCounterSec(final int nextPollDelayInSec) { public void setNextPollCounterSec(final int nextPollDelayInSec) {
this.nextPollCounterSec = 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; package org.eclipse.hawkbit.simulator;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.eclipse.hawkbit.simulator.http.ControllerResource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -18,7 +16,7 @@ import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException; 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 { public class DDISimulatedDevice extends AbstractSimulatedDevice {
@@ -26,12 +24,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class); private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class);
private final int pollDelaySec; private final int pollDelaySec;
private final ScheduledExecutorService pollthreadpool;
private final ControllerResource controllerResource; private final ControllerResource controllerResource;
private final DeviceSimulatorUpdater deviceUpdater;
private volatile boolean removed; private volatile boolean removed;
private volatile Long currentActionId; private volatile Long currentActionId;
private final DeviceSimulatorUpdater deviceUpdater;
/** /**
* @param id * @param id
@@ -42,18 +40,14 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
* the delay of the poll interval in sec * the delay of the poll interval in sec
* @param controllerResource * @param controllerResource
* the http controller resource * the http controller resource
* @param pollthreadpool
* the threadpool for polling endpoint
* @param deviceUpdater * @param deviceUpdater
* the service to update devices * the service to update devices
*/ */
public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec, public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec,
final ControllerResource controllerResource, final ScheduledExecutorService pollthreadpool, final ControllerResource controllerResource, final DeviceSimulatorUpdater deviceUpdater) {
final DeviceSimulatorUpdater deviceUpdater) {
super(id, tenant, Protocol.DDI_HTTP); super(id, tenant, Protocol.DDI_HTTP);
this.pollDelaySec = pollDelaySec; this.pollDelaySec = pollDelaySec;
this.controllerResource = controllerResource; this.controllerResource = controllerResource;
this.pollthreadpool = pollthreadpool;
this.deviceUpdater = deviceUpdater; this.deviceUpdater = deviceUpdater;
setNextPollCounterSec(pollDelaySec); setNextPollCounterSec(pollDelaySec);
} }
@@ -76,27 +70,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
final String basePollJson = controllerResource.get(getTenant(), getId()); final String basePollJson = controllerResource.get(getTenant(), getId());
try { try {
final String href = JsonPath.parse(basePollJson).read("_links.deploymentBase.href"); 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) { if (currentActionId == null) {
final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId); final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId);
final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version"); final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version");
currentActionId = actionId; currentActionId = actionId;
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, (device, actionId1) -> { startDdiUpdate(actionId, swVersion);
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;
});
} }
} catch (final PathNotFoundException e) { } catch (final PathNotFoundException e) {
// href might not be in the json response, so ignore // 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; package org.eclipse.hawkbit.simulator;
/** /**
* An simulated device using the DMF API of the hawkbit update server. * A simulated device using the DMF API of the hawkBit update server.
*
* @author Michael Hirsch
*
*/ */
public class DMFSimulatedDevice extends AbstractSimulatedDevice { 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. * The main-method to start the Spring-Boot application.
* *
*
*
*/ */
@SpringBootApplication @SpringBootApplication
@EnableVaadin @EnableVaadin
@@ -46,6 +44,8 @@ public class DeviceSimulator {
* @param args * @param args
* the args * the args
*/ */
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) { public static void main(final String[] args) {
SpringApplication.run(DeviceSimulator.class, args); SpringApplication.run(DeviceSimulator.class, args);
} }

View File

@@ -8,32 +8,65 @@
*/ */
package org.eclipse.hawkbit.simulator; 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.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; 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.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate; import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate; 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.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus; 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 @Service
public class DeviceSimulatorUpdater { public class DeviceSimulatorUpdater {
private static final Logger LOGGER = LoggerFactory.getLogger(DeviceSimulatorUpdater.class);
private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4); private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4);
@Autowired @Autowired
private SpSenderService spSenderService; private SpSenderService spSenderService;
@Autowired
private SimulatedDeviceFactory deviceFactory;
@Autowired @Autowired
private EventBus eventbus; private EventBus eventbus;
@@ -50,24 +83,43 @@ public class DeviceSimulatorUpdater {
* @param actionId * @param actionId
* the actionId from the hawkbit update server to start the * the actionId from the hawkbit update server to start the
* update. * update.
* @param swVersion * @param modules
* the software module version from the hawkbit update server * 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 * @param callback
* the callback which gets called when the simulated update * the callback which gets called when the simulated update
* process has been finished * process has been finished
*/ */
public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion, public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion,
final UpdaterCallback callback) { final List<SoftwareModule> modules, final String targetSecurityToken, final UpdaterCallback callback) {
final AbstractSimulatedDevice device = repository.get(tenant, id); 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.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)); eventbus.post(new InitUpdate(device));
threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), threadPool.schedule(
2_000, TimeUnit.MILLISECONDS); new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules), 2_000,
TimeUnit.MILLISECONDS);
} }
private static final class DeviceSimulatorUpdateThread implements Runnable { private static final class DeviceSimulatorUpdateThread implements Runnable {
private static final int MINIMUM_TOKENLENGTH_FOR_HINT = 6;
private static final Random rndSleep = new SecureRandom(); private static final Random rndSleep = new SecureRandom();
private final AbstractSimulatedDevice device; private final AbstractSimulatedDevice device;
@@ -75,38 +127,211 @@ public class DeviceSimulatorUpdater {
private final long actionId; private final long actionId;
private final EventBus eventbus; private final EventBus eventbus;
private final UpdaterCallback callback; private final UpdaterCallback callback;
private final List<SoftwareModule> modules;
private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService, 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.device = device;
this.spSenderService = spSenderService; this.spSenderService = spSenderService;
this.actionId = actionId; this.actionId = actionId;
this.eventbus = eventbus; this.eventbus = eventbus;
this.callback = callback; this.callback = callback;
this.modules = modules;
} }
@Override @Override
public void run() { 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; final double newProgress = device.getProgress() + 0.2;
device.setProgress(newProgress); device.setProgress(newProgress);
if (newProgress < 1.0) { if (newProgress < 1.0) {
threadPool.schedule( threadPool.schedule(
new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules),
rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS); rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS);
} else { } else {
callback.updateFinished(device, actionId); callback.updateFinished(device, actionId);
} }
eventbus.post(new ProgressUpdate(device)); 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 * Callback interface which is called when the simulated update process has
* been finished and the caller of starting the simulated update process can * been finished and the caller of starting the simulated update process can
* send the result to the hawkbit update server back. * send the result back to the hawkBit update server.
*
* @author Michael Hirsch
*
*/ */
@FunctionalInterface @FunctionalInterface
public interface UpdaterCallback { 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 * Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every
* second. * second.
*
* @author Michael Hirsch
*
*/ */
@Component @Component
public class NextPollTimeController { public class NextPollTimeController {
@@ -59,16 +56,15 @@ public class NextPollTimeController {
devices.forEach(device -> { devices.forEach(device -> {
int nextCounter = device.getNextPollCounterSec() - 1; int nextCounter = device.getNextPollCounterSec() - 1;
if (nextCounter < 0) { if (nextCounter < 0 && device instanceof DDISimulatedDevice) {
if (device instanceof DDISimulatedDevice) { try {
try { pollService.submit(() -> ((DDISimulatedDevice) device).poll());
pollService.submit(() -> ((DDISimulatedDevice) device).poll()); } catch (final IllegalStateException e) {
} catch (final IllegalStateException e) { LOGGER.trace("Device could not be polled", e);
LOGGER.trace("Device could not be polled", e);
}
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
} }
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
} }
device.setNextPollCounterSec(nextCounter); device.setNextPollCounterSec(nextCounter);
}); });
eventBus.post(new NextPollCounterUpdate(devices)); eventBus.post(new NextPollCounterUpdate(devices));

View File

@@ -9,8 +9,6 @@
package org.eclipse.hawkbit.simulator; package org.eclipse.hawkbit.simulator;
import java.net.URL; 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.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.eclipse.hawkbit.simulator.http.ControllerResource;
@@ -24,15 +22,9 @@ import feign.Logger;
/** /**
* The simulated device factory to create either {@link DMFSimulatedDevice} or * The simulated device factory to create either {@link DMFSimulatedDevice} or
* {@link DDISimulatedDevice#}. * {@link DDISimulatedDevice#}.
*
* @author Michael Hirsch
*
*/ */
@Service @Service
public class SimulatedDeviceFactory { public class SimulatedDeviceFactory {
private static final ScheduledExecutorService pollThreadPool = Executors.newScheduledThreadPool(4);
@Autowired @Autowired
private DeviceSimulatorUpdater deviceUpdater; private DeviceSimulatorUpdater deviceUpdater;
@@ -47,7 +39,8 @@ public class SimulatedDeviceFactory {
* the protocol of the device * the protocol of the device
* @return the created simulated 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); return createSimulatedDevice(id, tenant, protocol, 30, null, null);
} }
@@ -80,7 +73,7 @@ public class SimulatedDeviceFactory {
final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger()) final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger())
.requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC) .requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC)
.target(ControllerResource.class, baseEndpoint.toString()); .target(ControllerResource.class, baseEndpoint.toString());
return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, pollThreadPool, deviceUpdater); return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, deviceUpdater);
default: default:
throw new IllegalArgumentException("Protocol " + protocol + " unknown"); 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 * number of delay in milliseconds to delay polling of DDI
* devices * devices
* @param gatewayToken * @param gatewayToken
* the hawkbit-update-server gatwaytoken in case authentication * the hawkbit-update-server gatewaytoken in case authentication
* is enforced in hawkbit * is enforced in hawkbit
* @return a response string that devices has been created * @return a response string that devices has been created
* @throws MalformedURLException * @throws MalformedURLException
@@ -68,7 +68,7 @@ public class SimulationController {
@RequestParam(value = "endpoint", defaultValue = "http://localhost:8080") final String endpoint, @RequestParam(value = "endpoint", defaultValue = "http://localhost:8080") final String endpoint,
@RequestParam(value = "polldelay", defaultValue = "30") final int pollDelay, @RequestParam(value = "polldelay", defaultValue = "30") final int pollDelay,
@RequestParam(value = "gatewaytoken", defaultValue = "") final String gatewayToken) @RequestParam(value = "gatewaytoken", defaultValue = "") final String gatewayToken)
throws MalformedURLException { throws MalformedURLException {
final Protocol protocol; final Protocol protocol;
switch (api.toLowerCase()) { switch (api.toLowerCase()) {
@@ -86,7 +86,10 @@ public class SimulationController {
final String deviceId = name + i; final String deviceId = name + i;
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint), repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint),
gatewayToken)); gatewayToken));
spSenderService.createOrUpdateThing(tenant, deviceId);
if (protocol == Protocol.DMF_AMQP) {
spSenderService.createOrUpdateThing(tenant, deviceId);
}
} }
return ResponseEntity.ok("Updated " + amount + " DMF connected targets!"); 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 * @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 * @return the exchange
*/ */

View File

@@ -19,26 +19,31 @@ import org.springframework.stereotype.Component;
@Component @Component
@ConfigurationProperties("hawkbit.device.simulator.amqp") @ConfigurationProperties("hawkbit.device.simulator.amqp")
public class AmqpProperties { public class AmqpProperties {
/** /**
* Queue for receiving DMF messages from update server. * Queue for receiving DMF messages from update server.
*/ */
private String receiverConnectorQueueFromSp; private String receiverConnectorQueueFromSp = "simulator_receiver";
/** /**
* Exchange for sending DMF messages to update server. * Exchange for sending DMF messages to update server.
*/ */
private String senderForSpExchange; private String senderForSpExchange = "simulator.replyTo";
/** /**
* Simulator dead letter queue. * Simulator dead letter queue.
*/ */
private String deadLetterQueue; private String deadLetterQueue = "simulator_deadletter";
/** /**
* Simulator dead letter exchange. * 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() { public String getReceiverConnectorQueueFromSp() {
return receiverConnectorQueueFromSp; return receiverConnectorQueueFromSp;
@@ -71,4 +76,12 @@ public class AmqpProperties {
public void setSenderForSpExchange(final String senderForSpExchange) { public void setSenderForSpExchange(final String senderForSpExchange) {
this.senderForSpExchange = 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.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component; 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 @Component
public class SpReceiverService extends ReceiverService { public class SpReceiverService extends ReceiverService {
private static final Logger LOGGER = LoggerFactory.getLogger(ReceiverService.class); private static final Logger LOGGER = LoggerFactory.getLogger(ReceiverService.class);
public static final String SOFTWARE_MODULE_FIRMWARE = "firmware"; public static final String SOFTWARE_MODULE_FIRMWARE = "firmware";
@@ -44,17 +43,6 @@ public class SpReceiverService extends ReceiverService {
/** /**
* Constructor. * 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 @Autowired
public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties, public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties,
@@ -62,12 +50,11 @@ public class SpReceiverService extends ReceiverService {
super(rabbitTemplate, amqpProperties); super(rabbitTemplate, amqpProperties);
this.spSenderService = spSenderService; this.spSenderService = spSenderService;
this.deviceUpdater = deviceUpdater; this.deviceUpdater = deviceUpdater;
} }
/** /**
* Handle the incoming Message from Queue with the property * Handle the incoming Message from Queue with the property
* (com.bosch.sp.lwm2m.connector.amqp.receiverConnectorQueueFromSp). * (hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp).
* *
* @param message * @param message
* the incoming message * the incoming message
@@ -103,6 +90,8 @@ public class SpReceiverService extends ReceiverService {
if (eventHeader == null) { if (eventHeader == null) {
logAndThrowMessageError(message, "Event Topic is not set"); logAndThrowMessageError(message, "Event Topic is not set");
} }
// Exception squid:S2259 - Checked before
@SuppressWarnings({ "squid:S2259" })
final EventTopic eventTopic = EventTopic.valueOf(eventHeader.toString()); final EventTopic eventTopic = EventTopic.valueOf(eventHeader.toString());
switch (eventTopic) { switch (eventTopic) {
case DOWNLOAD_AND_INSTALL: case DOWNLOAD_AND_INSTALL:
@@ -124,7 +113,7 @@ public class SpReceiverService extends ReceiverService {
final Long actionId = convertMessage(message, Long.class); final Long actionId = convertMessage(message, Long.class);
final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId); 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) { private void handleUpdateProcess(final Message message, final String thingId) {
@@ -135,19 +124,20 @@ public class SpReceiverService extends ReceiverService {
final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message, final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message,
DownloadAndUpdateRequest.class); DownloadAndUpdateRequest.class);
final Long actionId = downloadAndUpdateRequest.getActionId(); final Long actionId = downloadAndUpdateRequest.getActionId();
final String targetSecurityToken = downloadAndUpdateRequest.getTargetSecurityToken();
deviceUpdater.startUpdate(tenant, thingId, actionId, deviceUpdater.startUpdate(tenant, thingId, actionId, null, downloadAndUpdateRequest.getSoftwareModules(),
downloadAndUpdateRequest.getSoftwareModules().get(0).getModuleVersion(), (device, actionId1) -> { targetSecurityToken, (device, actionId1) -> {
switch (device.getResponseStatus()) { switch (device.getUpdateStatus().getResponseStatus()) {
case SUCCESSFUL: case SUCCESSFUL:
spSenderService.finishUpdateProcess( spSenderService.finishUpdateProcess(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete!"); device.getUpdateStatus().getStatusMessages());
break; break;
case ERROR: case ERROR:
spSenderService.finishUpdateProcessWithError( spSenderService.finishUpdateProcessWithError(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete with error!"); device.getUpdateStatus().getStatusMessages());
break; break;
default: default:
break; break;

View File

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

View File

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

View File

@@ -7,18 +7,17 @@
# http://www.eclipse.org/legal/epl-v10.html # http://www.eclipse.org/legal/epl-v10.html
# #
## Configuration for DMF communication
#########################################################################################
# PUBLIC configuration, i.e. can be changed by users at runtime (defaults provided here)
#########################################################################################
## Configuration for RabbitMQ communication
hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp=simulator_receiver hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp=simulator_receiver
hawkbit.device.simulator.amqp.deadLetterQueue=simulator_deadletter hawkbit.device.simulator.amqp.deadLetterQueue=simulator_deadletter
hawkbit.device.simulator.amqp.deadLetterExchange=simulator.deadletter hawkbit.device.simulator.amqp.deadLetterExchange=simulator.deadletter
hawkbit.device.simulator.amqp.senderForSpExchange=simulator.replyTo 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.username=guest
spring.rabbitmq.password=guest spring.rabbitmq.password=guest
spring.rabbitmq.virtualHost=/ 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 # 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 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: Or:
``` ```
run org eclipse.hawkbit.app.Start run org eclipse.hawkbit.app.Start
``` ```
## Usage ### Usage
The UI can be accessed via _http://localhost:8080/UI_. The Management UI can be accessed via http://localhost:8080/UI
The REST API can be accessed via _http://localhost:8080/rest/v1_. 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> <version>0.2.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>hawkbit-example-app</artifactId> <artifactId>hawkbit-example-app</artifactId>
<name>hawkBit :: Example App</name> <name>hawkBit-example :: UI Application</name>
<build> <build>
<plugins> <plugins>
@@ -39,6 +39,20 @@
</executions> </executions>
</plugin> </plugin>
</plugins> </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> </build>
<dependencies> <dependencies>
@@ -50,7 +64,12 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <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> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -82,16 +101,26 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- Log4j API and Core implementation required for binding -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId> <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>
<dependency> <dependency>
<groupId>org.springframework.security</groupId> <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 * 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 * the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in
* this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}. * this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}.
*
*
*
*/ */
@SpringUI(path = 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 { public class MyLoginUI extends HawkbitLoginUI {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.app; package org.eclipse.hawkbit.app;
import org.eclipse.hawkbit.ui.HawkbitUI; import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.UIEventProvider;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy; import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -28,12 +29,16 @@ import com.vaadin.spring.annotation.SpringUI;
*/ */
@SpringUI @SpringUI
@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET) @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 { public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Autowired @Autowired
public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus) { public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus,
super(new DelayedEventBusPushStrategy(eventBus, systemEventBus)); 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.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration; import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
import org.eclipse.hawkbit.controller.EnableDirectDeviceApi; import org.eclipse.hawkbit.ddi.EnableDdiApi;
import org.eclipse.hawkbit.rest.resource.EnableRestResources; import org.eclipse.hawkbit.mgmt.EnableMgmtApi;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@@ -24,8 +24,10 @@ import org.springframework.context.annotation.Import;
@SpringBootApplication @SpringBootApplication
@Import({ RepositoryApplicationConfiguration.class }) @Import({ RepositoryApplicationConfiguration.class })
@EnableHawkbitManagedSecurityConfiguration @EnableHawkbitManagedSecurityConfiguration
@EnableRestResources @EnableMgmtApi
@EnableDirectDeviceApi @EnableDdiApi
// Exception squid:S1118 - Spring boot standard behavior
@SuppressWarnings({ "squid:S1118" })
public class Start { public class Start {
/** /**
@@ -34,6 +36,8 @@ public class Start {
* @param args * @param args
* the VM arguments. * the VM arguments.
*/ */
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) { public static void main(final String[] args) {
SpringApplication.run(Start.class, 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 # http://www.eclipse.org/legal/epl-v10.html
# #
# DDI authentication configuration
hawkbit.server.ddi.security.authentication.anonymous.enabled=true hawkbit.server.ddi.security.authentication.anonymous.enabled=true
hawkbit.server.ddi.security.authentication.targettoken.enabled=false hawkbit.server.ddi.security.authentication.targettoken.enabled=true
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false 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 vaadin.servlet.productionMode=false
## Configuration for RabbitMQ integration ## Configuration for DMF/RabbitMQ integration
spring.profiles.active=amqp
spring.rabbitmq.username=guest spring.rabbitmq.username=guest
spring.rabbitmq.password=guest spring.rabbitmq.password=guest
spring.rabbitmq.virtualHost=/ spring.rabbitmq.virtualHost=/
spring.rabbitmq.host=localhost spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672 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.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver 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 * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html * 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; 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 * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html * 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.annotation.Annotation;
import java.lang.reflect.Method; 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; 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; import org.springframework.cloud.netflix.feign.FeignClient;
/** /**
* Client binding for the DistributionSet resource of the management API. * Client binding for the DistributionSet resource of the management API.
*/ */
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsets") @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)
public interface DistributionSetResourceClient extends DistributionSetRestApi { public interface MgmtDistributionSetClientResource extends MgmtDistributionSetRestApi {
} }

View File

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

View File

@@ -8,14 +8,15 @@
*/ */
package org.eclipse.hawkbit.mgmt.client.resource; 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; import org.springframework.cloud.netflix.feign.FeignClient;
/** /**
* Client binding for the DistributionSetType resource of the management API. * Client binding for the DistributionSetType resource of the management API.
* *
*/ */
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsettypes") @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)
public interface DistributionSetTypeResourceClient extends DistributionSetTypeRestApi { 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; 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; 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") @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE)
public interface SoftwareModuleResourceClient extends SoftwareModuleRestAPI { public interface MgmtDownloadClientResource extends MgmtDownloadRestApi {
} }

View File

@@ -8,13 +8,13 @@
*/ */
package org.eclipse.hawkbit.mgmt.client.resource; 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; import org.springframework.cloud.netflix.feign.FeignClient;
/** /**
* Client binding for the Rollout resource of the management API. * Client binding for the Rollout resource of the management API.
*/ */
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/rollouts") @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING)
public interface RolloutResourceClient extends RolloutRestApi { 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; 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; 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") @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)
public interface SoftwareModuleTypeResourceClient extends SoftwareModuleTypeRestApi { 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; 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; import org.springframework.cloud.netflix.feign.FeignClient;
/** /**
* Client binding for the Target resource of the management API. * Client binding for the Target resource of the management API.
*/ */
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targets") @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)
public interface TargetResourceClient extends TargetRestApi { public interface MgmtTargetClientResource extends MgmtTargetRestApi {
} }

View File

@@ -8,13 +8,13 @@
*/ */
package org.eclipse.hawkbit.mgmt.client.resource; 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; import org.springframework.cloud.netflix.feign.FeignClient;
/** /**
* Client binding for the TargetTag resource of the management API. * Client binding for the TargetTag resource of the management API.
*/ */
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targettags") @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING)
public interface TargetTagResourceClient extends TargetTagRestApi { 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.ArrayList;
import java.util.List; 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; import com.google.common.collect.Lists;
/** /**
* * Builder pattern for building {@link MgmtDistributionSetRequestBodyPost}.
* Builder pattern for building {@link DistributionSetRequestBodyPost}.
*
* @author Jonathan Knoblauch
*
*/ */
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class DistributionSetBuilder { public class DistributionSetBuilder {
private String name; private String name;
private String version; private String version;
private String type; private String type;
private String description;
private final List<MgmtSoftwareModuleAssigment> modules = new ArrayList<>();
/** /**
* @param name * @param name
@@ -38,6 +39,13 @@ public class DistributionSetBuilder {
return this; return this;
} }
public DistributionSetBuilder moduleByID(final Long id) {
final MgmtSoftwareModuleAssigment softwareModuleAssigmentRest = new MgmtSoftwareModuleAssigment();
softwareModuleAssigmentRest.setId(id);
modules.add(softwareModuleAssigmentRest);
return this;
}
/** /**
* @param version * @param version
* the version of the distribution set * the version of the distribution set
@@ -59,28 +67,38 @@ public class DistributionSetBuilder {
} }
/** /**
* Builds a list with a single entry of * @param description
* {@link DistributionSetRequestBodyPost} which can directly be used to post * the description
* on the RESTful-API. * @return the builder itself
*
* @return a single entry list of {@link DistributionSetRequestBodyPost}
*/ */
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)); 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 * create multiple distribution sets at once. An increasing number will be
* added to the name of the distribution set. The version and type will * added to the name of the distribution set. The version and type will
* remain the same. * remain the same.
* *
* @param count * @param count
* the amount of distribution sets body which should be created * 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) { public List<MgmtDistributionSetRequestBodyPost> buildAsList(final int count) {
final ArrayList<DistributionSetRequestBodyPost> bodyList = Lists.newArrayList(); final ArrayList<MgmtDistributionSetRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) { for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index)); bodyList.add(doBuild(name + index));
} }
@@ -88,11 +106,13 @@ public class DistributionSetBuilder {
return bodyList; return bodyList;
} }
private DistributionSetRequestBodyPost doBuild(final String prefixName) { private MgmtDistributionSetRequestBodyPost doBuild(final String prefixName) {
final DistributionSetRequestBodyPost body = new DistributionSetRequestBodyPost(); final MgmtDistributionSetRequestBodyPost body = new MgmtDistributionSetRequestBodyPost();
body.setName(prefixName); body.setName(prefixName);
body.setVersion(version); body.setVersion(version);
body.setType(type); body.setType(type);
body.setDescription(description);
body.setModules(modules);
return body; return body;
} }

View File

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

View File

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

View File

@@ -11,15 +11,15 @@ package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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}. * Builder pattern for building {@link MgmtSoftwareModuleAssigment}.
*
* @author Jonathan Knoblauch
* *
*/ */
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class SoftwareModuleAssigmentBuilder { public class SoftwareModuleAssigmentBuilder {
private final List<Long> ids; 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. * 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() { public List<MgmtSoftwareModuleAssigment> build() {
final List<SoftwareModuleAssigmentRest> softwareModuleAssigmentRestList = new ArrayList<>(); final List<MgmtSoftwareModuleAssigment> softwareModuleAssigmentRestList = new ArrayList<>();
for (final Long id : ids) { for (final Long id : ids) {
final SoftwareModuleAssigmentRest softwareModuleAssigmentRest = new SoftwareModuleAssigmentRest(); final MgmtSoftwareModuleAssigment softwareModuleAssigmentRest = new MgmtSoftwareModuleAssigment();
softwareModuleAssigmentRest.setId(id); softwareModuleAssigmentRest.setId(id);
softwareModuleAssigmentRestList.add(softwareModuleAssigmentRest); softwareModuleAssigmentRestList.add(softwareModuleAssigmentRest);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,8 +8,7 @@
http://www.eclipse.org/legal/epl-v10.html 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" <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">
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> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
@@ -19,13 +18,45 @@
</parent> </parent>
<artifactId>hawkbit-examples-parent</artifactId> <artifactId>hawkbit-examples-parent</artifactId>
<name>hawkBit :: Examples Parent</name> <name>hawkBit-example :: Parent</name>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>hawkbit-device-simulator</module> <module>hawkbit-device-simulator</module>
<module>hawkbit-example-app</module> <module>hawkbit-example-app</module>
<module>hawkbit-mgmt-api-client</module> <module>hawkbit-example-core-feign-client</module>
</modules> <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> </project>

View File

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

View File

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

View File

@@ -64,7 +64,13 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <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> <version>${project.version}</version>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>

View File

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

View File

@@ -9,6 +9,9 @@
package org.eclipse.hawkbit.autoconfigure.ui; package org.eclipse.hawkbit.autoconfigure.ui;
import org.eclipse.hawkbit.DistributedResourceBundleMessageSource; 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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.vaadin.spring.annotation.EnableVaadinExtensions; import org.vaadin.spring.annotation.EnableVaadinExtensions;
@@ -17,9 +20,6 @@ import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
/** /**
* The hawkbit-ui autoconfiguration. * The hawkbit-ui autoconfiguration.
*
*
*
*/ */
@Configuration @Configuration
@EnableVaadinSecurity @EnableVaadinSecurity
@@ -37,4 +37,15 @@ public class UIAutoConfiguration {
return new DistributedResourceBundleMessageSource(); 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; package org.eclipse.hawkbit.autoconfigure.web;
import org.eclipse.hawkbit.controller.EnableDirectDeviceApi; import org.eclipse.hawkbit.ddi.EnableDdiApi;
import org.eclipse.hawkbit.rest.resource.EnableRestResources; import org.eclipse.hawkbit.mgmt.EnableMgmtApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
/** /**
* Auto-Configuration for enabling the REST-Resources. * Auto-Configuration for enabling the REST-Resources.
*
*
* *
*/ */
@Configuration @Configuration
@ConditionalOnClass({ EnableDirectDeviceApi.class, EnableRestResources.class }) @ConditionalOnClass({ EnableDdiApi.class, EnableMgmtApi.class })
@Import({ EnableDirectDeviceApi.class, EnableRestResources.class }) @Import({ EnableDdiApi.class, EnableMgmtApi.class })
public class ResourceControllerAutoConfiguration { public class ResourceControllerAutoConfiguration {
} }

View File

@@ -42,6 +42,6 @@ hawkbit.controller.minPollingTime=00:00:30
# Configuration for RabbitMQ integration # 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.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver 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 * Maximum polling time that can be configured by a tenant in HH:MM:SS
* notation. * 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 * 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