Merge remote-tracking branch 'origin/master'

This commit is contained in:
Kai Zimmermann
2016-03-28 07:15:20 +02:00
495 changed files with 26636 additions and 9556 deletions

7
.gitignore vendored
View File

@@ -16,8 +16,13 @@
*.jar
*.war
# Eclipse IDE
# Sonar
.sonar_lock
# Created by spring-boot-configuration-processor
.factorypath
# Eclipse IDE
*.pydevproject
.project
.metadata

View File

@@ -0,0 +1,3 @@
# 3rd Party Dependencies
Contains listing of all maven (transient) licenses of the project. Is primary used to identify all changes between eclipse releases.

View File

@@ -1,74 +1,95 @@
aopalliance:aopalliance:jar:1.0:compile
com.fasterxml.jackson.core:jackson-annotations:jar:2.5.0:compile
com.fasterxml.jackson.core:jackson-core:jar:2.5.0:compile
com.fasterxml.jackson.core:jackson-databind:jar:2.5.0:compile
com.fasterxml:classmate:jar:1.3.0:compile
com.google.guava:guava:jar:18.0:compile
com.h2database:h2:jar:1.4.186:compile
ch.qos.logback:logback-classic:jar:1.1.3:compile
ch.qos.logback:logback-core:jar:1.1.3:compile
com.fasterxml.jackson.core:jackson-annotations:jar:2.5.5:compile
com.fasterxml.jackson.core:jackson-core:jar:2.5.5:compile
com.fasterxml.jackson.core:jackson-databind:jar:2.5.5:compile
com.fasterxml:classmate:jar:1.1.0:compile
com.fasterxml:classmate:jar:1.2.0:compile
com.google.collections:google-collections:jar:1.0-rc2:compile
com.google.guava:guava:jar:19.0:compile
com.h2database:h2:jar:1.4.190:compile
com.jayway.jsonpath:json-path:jar:0.9.1:compile
com.netflix.feign:feign-core:jar:8.12.1:compile
com.netflix.feign:feign-core:jar:8.14.2:compile
com.netflix.feign:feign-jackson:jar:8.14.1:compile
com.netflix.feign:feign-ribbon:jar:8.1.1:compile
com.netflix.feign:feign-slf4j:jar:8.1.1:compile
com.netflix.ribbon:ribbon-core:jar:2.0.0:compile
com.netflix.ribbon:ribbon-httpclient:jar:2.0.0:compile
com.netflix.ribbon:ribbon-loadbalancer:jar:2.0.0:compile
com.netflix.ribbon:ribbon:jar:2.0.0:compile
com.rabbitmq:amqp-client:jar:3.5.5:compile
com.vaadin.external.atmosphere:atmosphere-runtime:jar:2.2.7.vaadin1:compile
com.vaadin.external.flute:flute:jar:1.3.0.gg2:compile
com.vaadin.external.google:guava:jar:16.0.1.vaadin1:compile
com.vaadin.external.slf4j:vaadin-slf4j-jdk14:jar:1.6.1:compile
com.vaadin.external.streamhtmlparser:streamhtmlparser-jsilver:jar:0.0.10.vaadin1:compile
com.vaadin:vaadin-push:jar:7.5.7:compile
com.vaadin:vaadin-sass-compiler:jar:0.9.12:compile
com.vaadin:vaadin-server:jar:7.5.7:compile
com.vaadin:vaadin-shared:jar:7.5.7:compile
com.vaadin:vaadin-client-compiled:jar:7.6.3:compile
com.vaadin:vaadin-push:jar:7.6.3:compile
com.vaadin:vaadin-sass-compiler:jar:0.9.13:compile
com.vaadin:vaadin-server:jar:7.6.3:compile
com.vaadin:vaadin-shared:jar:7.6.3:compile
com.vaadin:vaadin-spring-boot-starter:jar:1.0.0:compile
com.vaadin:vaadin-spring-boot:jar:1.0.0:compile
com.vaadin:vaadin-spring:jar:1.0.0:compile
com.vaadin:vaadin-themes:jar:7.5.7:compile
com.vaadin:vaadin-themes:jar:7.6.3:compile
com.yahoo.platform.yui:yuicompressor:jar:2.4.8:compile
commons-io:commons-io:jar:2.4:compile
cz.jirutka.rsql:rsql-parser:jar:2.0.0:compile
io.reactivex:rxjava:jar:1.0.11:compile
io.springfox:springfox-core:jar:2.0.3:compile
io.springfox:springfox-schema:jar:2.0.3:compile
io.springfox:springfox-spi:jar:2.0.3:compile
io.springfox:springfox-spring-web:jar:2.0.3:compile
io.springfox:springfox-swagger-common:jar:2.0.3:compile
io.springfox:springfox-swagger2:jar:2.0.3:compile
io.swagger:swagger-annotations:jar:1.5.0:compile
io.swagger:swagger-models:jar:1.5.0:compile
javax.servlet:javax.servlet-api:jar:3.1.0:compile
javax.transaction:javax.transaction-api:jar:1.2:compile
javax.validation:validation-api:jar:1.1.0.Final:compile
joda-time:joda-time:jar:2.5:compile
net._01001111:jlorem:jar:1.1:compile
net.minidev:json-smart:jar:1.2:compile
org.apache.commons:commons-lang3:jar:3.4:compile
org.apache.commons:commons-pool2:jar:2.2:compile
org.apache.logging.log4j:log4j-api:jar:2.1:compile
org.apache.logging.log4j:log4j-core:jar:2.1:compile
org.apache.logging.log4j:log4j-slf4j-impl:jar:2.1:compile
org.apache.tomcat:tomcat-jdbc:jar:8.0.28:compile
org.apache.tomcat:tomcat-juli:jar:8.0.28:compile
org.apache.tomcat:tomcat-jdbc:jar:8.0.30:compile
org.apache.tomcat:tomcat-juli:jar:8.0.30:compile
org.aspectj:aspectjrt:jar:1.8.5:compile
org.aspectj:aspectjweaver:jar:1.8.5:compile
org.eclipse.persistence:javax.persistence:jar:2.1.0:compile
org.eclipse.persistence:org.eclipse.persistence.antlr:jar:2.6.0:compile
org.eclipse.persistence:org.eclipse.persistence.asm:jar:2.6.0:compile
org.eclipse.persistence:org.eclipse.persistence.core:jar:2.6.0:compile
org.eclipse.persistence:org.eclipse.persistence.jpa.jpql:jar:2.6.0:compile
org.eclipse.persistence:org.eclipse.persistence.jpa:jar:2.6.0:compile
org.eclipse.persistence:javax.persistence:jar:2.1.1:compile
org.eclipse.persistence:org.eclipse.persistence.antlr:jar:2.6.2:compile
org.eclipse.persistence:org.eclipse.persistence.asm:jar:2.6.2:compile
org.eclipse.persistence:org.eclipse.persistence.core:jar:2.6.2:compile
org.eclipse.persistence:org.eclipse.persistence.jpa.jpql:jar:2.6.2:compile
org.eclipse.persistence:org.eclipse.persistence.jpa:jar:2.6.2:compile
org.flywaydb:flyway-core:jar:3.1:compile
org.glassfish:javax.json:jar:1.0.4:compile
org.hibernate:hibernate-validator:jar:5.2.2.Final:compile
org.hibernate:hibernate-validator:jar:5.2.4.Final:compile
org.jboss.logging:jboss-logging:jar:3.2.1.Final:compile
org.jsoup:jsoup:jar:1.8.1:compile
org.mapstruct:mapstruct:jar:1.0.0.Beta4:compile
org.mongodb:mongo-java-driver:jar:3.0.2:compile
org.json:json:jar:20141113:compile
org.jsoup:jsoup:jar:1.8.3:compile
org.mongodb:mongo-java-driver:jar:3.2.2:compile
org.objenesis:objenesis:jar:2.1:compile
org.slf4j:jcl-over-slf4j:jar:1.7.12:compile
org.slf4j:jul-to-slf4j:jar:1.7.12:compile
org.slf4j:slf4j-api:jar:1.7.7:compile
org.slf4j:jcl-over-slf4j:jar:1.7.13:compile
org.slf4j:jul-to-slf4j:jar:1.7.13:compile
org.slf4j:log4j-over-slf4j:jar:1.7.13:compile
org.slf4j:slf4j-api:jar:1.7.13:compile
org.springframework.amqp:spring-amqp:jar:1.4.6.RELEASE:compile
org.springframework.amqp:spring-rabbit:jar:1.4.6.RELEASE:compile
org.springframework.boot:spring-boot-autoconfigure:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot-starter-aop:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot-starter-data-jpa:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot-starter-jdbc:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot-starter-log4j2:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot-starter-web:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot-starter:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot:jar:1.2.7.RELEASE:compile
org.springframework.boot:spring-boot-autoconfigure:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-configuration-processor:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-starter-aop:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-starter-data-jpa:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-starter-jdbc:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-starter-log4j2:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-starter-logging:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-starter-web:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot-starter:jar:1.2.8.RELEASE:compile
org.springframework.boot:spring-boot:jar:1.2.8.RELEASE:compile
org.springframework.cloud:spring-cloud-commons:jar:1.0.5.RELEASE:compile
org.springframework.cloud:spring-cloud-context:jar:1.0.5.RELEASE:compile
org.springframework.cloud:spring-cloud-netflix-core:jar:1.0.7.RELEASE:compile
org.springframework.cloud:spring-cloud-starter-feign:jar:1.0.6.RELEASE:compile
org.springframework.cloud:spring-cloud-starter-ribbon:jar:1.0.6.RELEASE:compile
org.springframework.cloud:spring-cloud-starter:jar:1.0.5.RELEASE:compile
org.springframework.data:spring-data-commons:jar:1.10.1.RELEASE:compile
org.springframework.data:spring-data-jpa:jar:1.8.1.RELEASE:compile
org.springframework.data:spring-data-mongodb:jar:1.7.1.RELEASE:compile
@@ -77,29 +98,33 @@
org.springframework.plugin:spring-plugin-core:jar:1.1.0.RELEASE:compile
org.springframework.plugin:spring-plugin-metadata:jar:1.2.0.RELEASE:compile
org.springframework.retry:spring-retry:jar:1.1.2.RELEASE:compile
org.springframework.security:spring-security-aspects:jar:3.2.8.RELEASE:compile
org.springframework.security:spring-security-config:jar:3.2.8.RELEASE:compile
org.springframework.security:spring-security-core:jar:3.2.8.RELEASE:compile
org.springframework.security:spring-security-web:jar:3.2.8.RELEASE:compile
org.springframework:spring-aop:jar:4.1.8.RELEASE:compile
org.springframework:spring-aspects:jar:4.1.8.RELEASE:compile
org.springframework:spring-beans:jar:4.1.8.RELEASE:compile
org.springframework:spring-context-support:jar:4.1.8.RELEASE:compile
org.springframework:spring-context:jar:4.1.8.RELEASE:compile
org.springframework:spring-core:jar:4.1.8.RELEASE:compile
org.springframework:spring-expression:jar:4.1.8.RELEASE:compile
org.springframework:spring-jdbc:jar:4.1.8.RELEASE:compile
org.springframework:spring-messaging:jar:4.1.8.RELEASE:compile
org.springframework:spring-orm:jar:4.1.8.RELEASE:compile
org.springframework:spring-tx:jar:4.1.8.RELEASE:compile
org.springframework:spring-web:jar:4.1.8.RELEASE:compile
org.springframework:spring-webmvc:jar:4.1.8.RELEASE:compile
org.springframework.security:spring-security-aspects:jar:3.2.9.RELEASE:compile
org.springframework.security:spring-security-config:jar:3.2.9.RELEASE:compile
org.springframework.security:spring-security-core:jar:3.2.9.RELEASE:compile
org.springframework.security:spring-security-crypto:jar:3.2.9.RELEASE:compile
org.springframework.security:spring-security-web:jar:3.2.9.RELEASE:compile
org.springframework:spring-aop:jar:4.1.9.RELEASE:compile
org.springframework:spring-aspects:jar:4.1.9.RELEASE:compile
org.springframework:spring-beans:jar:4.1.9.RELEASE:compile
org.springframework:spring-context-support:jar:4.1.9.RELEASE:compile
org.springframework:spring-context:jar:4.1.9.RELEASE:compile
org.springframework:spring-core:jar:4.1.9.RELEASE:compile
org.springframework:spring-expression:jar:4.1.9.RELEASE:compile
org.springframework:spring-jdbc:jar:4.1.9.RELEASE:compile
org.springframework:spring-messaging:jar:4.1.9.RELEASE:compile
org.springframework:spring-orm:jar:4.1.9.RELEASE:compile
org.springframework:spring-tx:jar:4.1.9.RELEASE:compile
org.springframework:spring-web:jar:4.1.9.RELEASE:compile
org.springframework:spring-webmvc:jar:4.1.9.RELEASE:compile
org.vaadin.addons.lazyquerycontainer:vaadin-lazyquerycontainer:jar:7.4.0.1:compile
org.vaadin.addons:contextmenu:jar:4.5:compile
org.vaadin.addons:flexibleoptiongroup:jar:2.2.0:compile
org.vaadin.addons:tokenfield:jar:7.0.1:compile
org.vaadin.alump.distributionbar:dbar-addon:jar:1.2.0:compile
org.vaadin.spring.addons:vaadin-spring-addon-eventbus:jar:0.0.6.RELEASE:compile
org.vaadin.spring.extensions:vaadin-spring-ext-core:jar:0.0.6.RELEASE:compile
org.vaadin.spring.extensions:vaadin-spring-ext-security:jar:0.0.6.RELEASE:compile
org.w3c.css:sac:jar:1.3:compile
org.yaml:snakeyaml:jar:1.14:compile
redis.clients:jedis:jar:2.5.2:compile
rhino:js:jar:1.7R2:compile

View File

@@ -6,3 +6,6 @@ find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:test'|sor
find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:provided'|sort|uniq > 3rd-dependencies/provided.txt
find . -name dependencies.txt|while read i; do rm $i;done
cd 3rd-dependencies/
cat compile.txt provided.txt|cut -d':' -f1-4|while read i; do grep -h $i test.txt;done|sort|uniq|while read x; do sed -i.bak -e s/$x// test.txt ;done
sed -i.bak '/^[[:space:]]*$/d' test.txt
rm *.bak

View File

@@ -1,6 +1,6 @@
javax.servlet:javax.servlet-api:jar:3.1.0:provided
org.apache.tomcat.embed:tomcat-embed-core:jar:8.0.28:provided
org.apache.tomcat.embed:tomcat-embed-el:jar:8.0.28:provided
org.apache.tomcat.embed:tomcat-embed-logging-juli:jar:8.0.28:provided
org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.0.28:provided
org.springframework.boot:spring-boot-starter-tomcat:jar:1.2.7.RELEASE:provided
org.apache.tomcat.embed:tomcat-embed-core:jar:8.0.30:provided
org.apache.tomcat.embed:tomcat-embed-el:jar:8.0.30:provided
org.apache.tomcat.embed:tomcat-embed-logging-juli:jar:8.0.30:provided
org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.0.30:provided
org.springframework.boot:spring-boot-starter-tomcat:jar:1.2.8.RELEASE:provided

View File

@@ -1,55 +1,36 @@
com.fasterxml.jackson.core:jackson-core:jar:2.5.0:test
com.fasterxml.jackson.core:jackson-databind:jar:2.5.0:test
com.github.fge:btf:jar:1.2:test
com.github.fge:jackson-coreutils:jar:1.6:test
com.github.fge:json-patch:jar:1.7:test
com.github.fge:msg-simple:jar:1.1:test
com.google.code.findbugs:jsr305:jar:2.0.1:test
com.h2database:h2:jar:1.4.186:test
com.jayway.jsonpath:json-path:jar:0.9.1:test
com.sun.jersey:jersey-client:jar:1.18.1:test
com.sun.jersey:jersey-core:jar:1.13:test
commons-beanutils:commons-beanutils-core:jar:1.8.3:test
commons-io:commons-io:jar:2.4:test
commons-logging:commons-logging:jar:1.1.1:test
de.flapdoodle.embed:de.flapdoodle.embed.mongo:jar:1.50.0:test
de.flapdoodle.embed:de.flapdoodle.embed.process:jar:1.50.0:test
io.swagger:swagger-annotations:jar:1.5.0:test
de.flapdoodle.embed:de.flapdoodle.embed.mongo:jar:1.50.2:test
de.flapdoodle.embed:de.flapdoodle.embed.process:jar:1.50.1:test
javax.el:javax.el-api:jar:2.2.4:test
junit:junit:jar:4.12:test
net.java.dev.jna:jna-platform:jar:4.0.0:test
net.java.dev.jna:jna:jar:3.3.0:test
net.java.dev.jna:jna:jar:4.0.0:test
net.java.dev.jna:jna:jar:platform:3.3.0:test
net.minidev:json-smart:jar:1.2:test
org.apache.commons:commons-compress:jar:1.3:test
org.apache.commons:commons-lang3:jar:3.1:test
org.apache.tika:tika-core:jar:1.7:test
org.aspectj:aspectjrt:jar:1.8.5:test
org.atteo:evo-inflector:jar:1.2.1:test
org.easytesting:fest-assert-core:jar:2.0M10:test
org.easytesting:fest-assert:jar:1.4:test
org.easytesting:fest-util:jar:1.2.5:test
org.hamcrest:hamcrest-core:jar:1.3:test
org.hamcrest:hamcrest-library:jar:1.3:test
org.json:json:jar:20141113:test
org.jvnet.jaxb2_commons:jaxb2-basics-runtime:jar:0.9.3:test
org.mariadb.jdbc:mariadb-java-client:jar:1.2.3:test
org.mariadb.jdbc:mariadb-java-client:jar:1.3.5:test
org.mockito:mockito-core:jar:1.10.19:test
org.objenesis:objenesis:jar:2.1:test
org.springframework.boot:spring-boot-starter-test:jar:1.2.7.RELEASE:test
org.springframework.boot:spring-boot-starter-test:jar:1.2.8.RELEASE:test
org.springframework.data:spring-data-rest-core:jar:2.3.1.RELEASE:test
org.springframework.data:spring-data-rest-webmvc:jar:2.3.1.RELEASE:test
org.springframework.hateoas:spring-hateoas:jar:0.16.0.RELEASE:test
org.springframework.plugin:spring-plugin-core:jar:1.1.0.RELEASE:test
org.springframework.security:spring-security-aspects:jar:3.2.8.RELEASE:test
org.springframework.security:spring-security-config:jar:3.2.8.RELEASE:test
org.springframework.security:spring-security-web:jar:3.2.8.RELEASE:test
org.springframework:spring-context-support:jar:4.1.8.RELEASE:test
org.springframework:spring-test:jar:4.1.8.RELEASE:test
org.springframework:spring-web:jar:4.1.8.RELEASE:test
org.springframework:spring-webmvc:jar:4.1.8.RELEASE:test
ru.yandex.qatools.allure:allure-java-adaptor-api:jar:1.4.15:test
ru.yandex.qatools.allure:allure-java-annotations:jar:1.4.15:test
ru.yandex.qatools.allure:allure-java-aspects:jar:1.4.15:test
ru.yandex.qatools.allure:allure-junit-adaptor:jar:1.4.15:test
ru.yandex.qatools.allure:allure-model:jar:1.4.15:test
org.springframework:spring-test:jar:4.1.9.RELEASE:test
ru.yandex.qatools.allure:allure-java-adaptor-api:jar:1.4.22:test
ru.yandex.qatools.allure:allure-java-annotations:jar:1.4.22:test
ru.yandex.qatools.allure:allure-java-aspects:jar:1.4.22:test
ru.yandex.qatools.allure:allure-junit-adaptor:jar:1.4.22:test
ru.yandex.qatools.allure:allure-model:jar:1.4.22:test
ru.yandex.qatools.properties:properties-loader:jar:1.5:test

View File

@@ -4,7 +4,9 @@
Please read this if you intend to contribute to the project.
## Code Conventions
## Conventions
### Code Style
* Java files:
* we follow the standard eclipse IDE (built in) code formatter with the following changes:
@@ -19,6 +21,37 @@ Please read this if you intend to contribute to the project.
* Sonarqube:
* Our rule set is defined [here](http://sonar.eu-gb.mybluemix.net)
### Test documentation
Please documented the test cases that you contribute by means of [Allure](http://allure.qatools.ru) annotations and proper test method naming.
All test classes are documented with [Allure's](https://github.com/allure-framework/allure-core/wiki/Features-and-Stories) **@Features** and **@Stories** annotations in the following format:
```
@Features("TEST_TYPE - HAWKBIT_COMPONENT")
@Stories("Test class description")
```
Test types are:
* Unit Tests - for single units tests with a mocked environment
* Component Tests - for complete components including lower layers, e.g. Spring MVC test on rest API including repository and database.
* Integration Tests - including clients, e.g. Selenium UI tests with various browsers.
* System Tests - on target environments, e.g. Cloud Foundry.
Examples for hawkBit components:
* Management API
* Direct Device Integration API
* Device Management Federation API
* Management UI
* Repository
* Security
```
@Features("Component Tests - Management API")
@Stories("Distribution Set Type Resource")
```
In addition all test method's name describes in **camel case** what the test is all about and has a long description aith Allures **@Description** annotation.
## Legal considerations for your contribution
The following steps are necessary to comply with the Eclipse Foundation's IP policy.

131
DDIA.md
View File

@@ -1,131 +0,0 @@
## Direct Device Integration API (HTTP)
This API is based on HTTP standards and based on a polling mechanism.
The hawkbit update server provides REST resources which are consumed by the device to retrieve software update tasks.
##### Base Poll Resource
```
GET /{tenant}/controller/v1/{controllerId}
```
In the answer to the baseUrl polling the backend can send action links. A possible action is a deploy command.
The client makes a GET request on the given link:
_Example Response_
```
{
"config": {
"polling": {
"sleep": "00:05:00"
}
},
"_links": {
"deploymentBase": {
"href": "http://localhost:8080/default/controller/v1/example/deploymentBase/1?c=644088541"
},
"configData": {
"href": "http://localhost:8080/default/controller/v1/example/configData"
}
}
}
```
##### Deployment Base Resource
```
GET /{tenant}/controller/v1/{controllerId}/deploymentBase/{id}
```
_Example Response_
```
{
"deployment": {
"download": "forced",
"update": "forced",
"chunks": [
{
"part": "os",
"version": "1.0.0",
"name": "Linux",
"artifacts": [
{
"filename": "linux.zip",
"hashes": {
"sha1": "46fc56de883ec027759d8513458fe1010aa7e793",
"md5": "5813e9655bd6871d0c25b8d510fd8605"
},
"size": 52167,
"_links": {
"download": {
"href": "http://localhost:8080/default/controller/v1/example/softwaremodules/1/artifacts/linux.zip"
},
"md5sum": {
"href": "http://localhost:8080/default/controller/v1/example/softwaremodules/1/artifacts/linux.zip.MD5SUM"
}
}
}
]
}
]
},
"id": "1"
}
```
##### Deployment Feedback Resource
To every deployment the client can post feedback back to the update-server about the deployment status.
```
POST /{tenant}/controller/v1/{controllerId}/deploymentBase/{id}/feedback
Content-Type: application/json
```
_Example Body Deployment Success_
```
{
"id": 1,
"time": "20140511T121314",
"status": {
"execution": "closed",
"result": {
"finished": "success",
"progress": {}
}
}
}
```
_Example Body Deployment Proceeding_
```
{
"id": "1",
"time": "20140511T121314",
"status": {
"execution": "proceeding",
"result": {
"finished": "none",
"progress": {
"cnt": 2,
"of": 5
}
},
"details": [
"checking hash sums"
]
}
}
```
_Example Body Deployment Error_
```
{
"id": 1,
"time": "20140511T121314",
"status": {
"execution": "rejected",
"result": {
"finished": "failure",
"progress": {}
},
"details": [
"something bad happend"
]
}
}
```

127
DMFA.md
View File

@@ -1,127 +0,0 @@
# !!! DRAFT !!! #
# Device Management Federation API #
This document describes the **DMF API**. This API is based on AMQP [(AMQP-Specification)](ht1tp://www.amqp.org/sites/amqp.org/files/amqp.pdf "AMQP-Specification"). The SP Update server provides a message queue (default: "*dmf_receiver*") on the corresponding Rabbit MQ service, which accepts all incoming messages.
Every Service, which wants to communicate, has to offer a own queue, to which the SP update server can send messages. The name of this queue is sent
## Authentication ##
???
## Regular update process ##
### Step 1: Creating a Thing on SP ###
At the beginning every connecting service has to register its targets at the Sp update server. During the creating process the service has to send the name of the queue, which accepts messages, which are sent back from the Sp update server.
The message which is sent by the connecting service to the SP update service has to fulfill the following format. The connecting service has to set the attributes in the header. The name of the tenent (*tenant*, an unique identifier of the thing/target (*thingId*) and an string which identifies the sending service (*sender*). Furthermore it has to set the *replyTo*-Property which defines the name of the queue, which receives messages sent by the SP Update Server. The body of the message is not analyzed and can be empty.
**Header**
<pre>
type=THING_CREATED
tenant=<b>#TENANTNAME#</b>
thingId=<b>#ExampleDevice001#</b>
sender=<b>#CONNECTORSERVICE#</b>
</pre>
**Properties**
<pre>
contentType=application/json
replyTo=<b>#queue.which.accepts.messages.from.sp#</b>
</pre>
**Example Body**
<pre> </pre>
### Step 2: Begin of update process ###
Afterwards an distribution set can be assigned to the created thing. This can be done on the UI or with the REST API. To start the update process the SP update server sends a message over the registered queue back to the connecting service.
Inside the message send from the Sp update service the header specifies the target which has to be updated. Therefor the *tenent* and the unique *thingId* are used. The body contains an identifier which defines the update process (*actionId*) and the information of the software modules. The *actionId* is important to send the progress of the update process to the server. The information about the software describes all modules which are included in the current update process, their identifier, their type, their version and the corresponding artifacts with the urls where the target can download the artifacts.
**Header**
<pre>
type=EVENT
tenant=<b>#TENANTNAME#</b>
thingId=<b>#ExampleDevice001#</b>
topic=DOWNLOAD_AND_INSTALL
</pre>
**Properties**
<pre>
contentType=application/json
</pre>
**Example Body**
<pre>
{
"actionId":172,
"softwareModules":[
{
"moduleId":6,
"moduleType":"firmware",
"moduleVersion":"7.7.7",
"artifacts":[
{
"urls":{
"coap":"coap://bumlux.test",
"http":"coap://bumlux.test"}
}]
}]
}
</pre>
### Step 3: Sending the state update process <a name="sendingactionstate"></a>###
During the update progress the connected service can inform the sp update service about the progress and eventual warnings or errors. Therefore the *actionId* and the *softwareModuleId* are used to specify for which process and for which software module the progress update is for. Additionally in the Body there is a field *actionStatus*. This field is used to describe the type of the progress update and there are several allowed values:
- **RETRIEVED**: general acknowledge message
- **DOWNLOAD**: describes all messages related to the download prorgess
- **RUNNING**:
- **WARNING**: A smaller problem which influence the update process, but no need for stop it.
- **ERROR**: A big issues which not allows continuing the update process.
- **FINISHED**: Successfully finished the update process.
- **CANCELED**: Response to a cancel request, when the process is canceled.
- **CANCEL_REJECTED**: Response to a cancel request, when canceling is not possible.
The update process is marked as running until the connected Server sends a **FINISHED**, an **ERROR** or a **CANCELED** message. Additionally the connected service can put some human readable information into the message, which describes the state of the action more detailed.
**Header**
<pre>
type=EVENT
tenant=<b>#TENANTNAME#</b>
topic=UPDATE_ACTION_STATUS
</pre>
**Properties**
<pre>
contentType=application/json
</pre>
**Example Body**
<pre>
{
"actionId":115,
"softwareModuleId":3,
"actionStatus":"DOWNLOAD",
"message":["The download has started"]
}
</pre>
## Cancel process ##
During the update process the SP update server has the chance to cancel an update. Therefore it sends the following message. This message includes the *tenant* and the corresponding *thingId* on theheader.
**Header**
<pre>
type=EVENT
tenant=<b>#TENANTNAME#</b>
thingId=<b>#ExampleDevice001#</b>
topic=CANCEL_DOWNLOAD
</pre>
**Properties**
<pre>
contentType=application/json
</pre>
**Example Body**
<pre>
</pre>
Receiving this message the connected service has to decide if an update can be canceled or not. If it is the update has to be canceled and a **CANCELED** message has to be sent to the SP server. Otherwise a **CANCEL_REJECTED** message has to be sent.
![](src/images/dmfa_cancel_response.png)

9
MIGRATION.md Normal file
View File

@@ -0,0 +1,9 @@
# hawkBit Migration Guides
## Release 0.2
### Configuration Property changes
- hawkbit.server.controller._ have changed to hawkbit.server.ddi._
- info.build._ have changed to hawkbit.server.build._
- hawkbit.server.demo._ have changed to hawkbit.server.ui.demo._
- hawkbit.server.email.support has changed to hawkbit.server.ui.links.support
- hawkbit.server.email.request.account has changed to hawkbit.server.ui.links.requestAccount
- hawkbit.server.im.login.url has changed to hawkbit.server.ui.links.userManagement

View File

@@ -4,21 +4,43 @@ Build: [![Circle CI](https://circleci.com/gh/eclipse/hawkbit.svg?style=svg)](htt
[hawkBit](https://projects.eclipse.org/projects/iot.hawkbit) is an domain independent back end solution for rolling out software updates to constrained edge devices as well as more powerful controllers and gateways connected to IP based networking infrastructure.
# Documentation
see [hawkBit Wiki](https://github.com/eclipse/hawkbit/wiki)
# Contact us
* Want to chat with the team behind hawkBit? [![Join the chat at https://gitter.im/eclipse/hawkbit](https://badges.gitter.im/eclipse/hawkbit.svg)](https://gitter.im/eclipse/hawkbit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
* 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.
# Compile
```
mvn install
```
# Run and use
# 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.
#### Clone and build hawkBit
```
$ git clone https://github.com/eclipse/hawkbit.git
$ cd hawkbit
$ mvn clean install
```
#### Start hawkBit example app
[Example Application](examples/hawkbit-example-app)
```
$ java -jar ./examples/hawkbit-example-app/target/hawkbit-example-app-#version#.jar
```
#### Start hawkBit device simulator
[Device Simulator](examples/hawkbit-device-simulator)
```
$ java -jar ./examples/hawkbit-device-simulator/target/hawkbit-device-simulator-#version#.jar
```
#### Generate Getting Started data
[Example Management API Client](examples/hawkbit-mgmt-api-client)
```
$ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#version#.jar
```
# Releases and Roadmap
* We are currently working on the first formal release under the Eclipse banner: 0.1 (see [Release 0.1 branch](https://github.com/eclipse/hawkbit/tree/release-train-0.1)).
@@ -29,12 +51,6 @@ We are not providing an off the shelf installation ready hawkBit update server.
* And of course tons of usability improvements and bug fixes.
## Try out examples
#### Standalone Test Application Server
[Example Application](examples/hawkbit-example-app)
#### Device Simulator using the DMF AMQP API
[Device Simulator](examples/hawkbit-device-simulator)
# Modules
`hawkbit-core` : core elements.
`hawkbit-security-core` : core security elements.
@@ -49,9 +65,3 @@ We are not providing an off the shelf installation ready hawkBit update server.
`hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API.
`hawkbit-ui` : Vaadin UI.
`hawkbit-cache-redis` : spring cache manager configuration and implementation with redis, distributed cache and distributed events.
# Device Integration
There are two device integration APIs provided by the hawkbit update server.
* [Direct Device Integration API (HTTP)](DDIA.md)
* [Device Management Federation API (AMQP)](DMFA.md)

View File

@@ -13,7 +13,7 @@ run org.eclipse.hawkbit.simulator.DeviceSimulator
## Notes
The simulator has user authentication enabled by default. Default credentials:
The simulator has user authentication enabled in **cloud profile**. Default credentials:
* username : admin
* passwd : admin
@@ -29,8 +29,6 @@ The UI can be accessed via the URL:
http://localhost:8083
```
`Basic Authentication Credentials are admin / admin`
![](src/main/images/generateScreenshot.png)
![](src/main/images/updateProcessScreenshot.png)
@@ -45,6 +43,10 @@ Optional parameters:
* name : name prefix simulated devices (default: "dmfSimulated"), followed by counter
* amount : number of simulated devices (default: 20, capped at: 4000)
* tenant : in a multi-tenenat ready hawkBit installation (default: "DEFAULT")
* api : the API which should be used for the simulated device either `dmf` or `ddi` (default: "ddi")
* endpoint : URL which defines the hawkbit DDI base endpoint (deffault: "http://localhost:8080")
* polldelay : number in milliseconds of the delay when DDI simulated devices should poll the endpoint (default: "30")
* gatewaytoken : an hawkbit gateway token to be used in case hawkbit does not allow anonymous access for DDI devices (default: "")
Example: for 20 simulated devices (default)
@@ -56,3 +58,8 @@ Example: for 10 simulated devices that start with the name prefix "activeSim":
```
http://localhost:8083/start?amount=10&name=activeSim
```
Example: for 5 simulated devices that start with the name prefix "ddi" using the Direct Device Integration API (http):
```
http://localhost:8083/start?amount=5&name=ddi?api=ddi
```

View File

@@ -100,7 +100,6 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
@@ -116,13 +115,18 @@
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>7.5.5</version>
<version>7.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.simulator;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater.UpdaterCallback;
import org.eclipse.hawkbit.simulator.http.ControllerResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -82,28 +81,27 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId);
final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version");
currentActionId = actionId;
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, new UpdaterCallback() {
@Override
public void updateFinished(final AbstractSimulatedDevice device, final Long actionId) {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
controllerResource.postSuccessFeedback(getTenant(), getId(), actionId);
break;
case ERROR:
controllerResource.postErrorFeedback(getTenant(), getId(), actionId);
break;
default:
throw new IllegalStateException("simulated device has an unknown response status + "
+ device.getResponseStatus());
}
currentActionId = null;
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, (device, actionId1) -> {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
controllerResource.postSuccessFeedback(getTenant(), getId(),
actionId1);
break;
case ERROR:
controllerResource.postErrorFeedback(getTenant(), getId(),
actionId1);
break;
default:
throw new IllegalStateException(
"simulated device has an unknown response status + " + device.getResponseStatus());
}
currentActionId = null;
});
}
} catch (final PathNotFoundException e) {
// href might not be in the json response, so ignore
// exception here.
LOGGER.trace("Response does not contain a deploymentbase href link, ignoring.");
LOGGER.trace("Response does not contain a deploymentbase href link, ignoring.", e);
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.simulator;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -41,7 +42,7 @@ public class DeviceSimulatorUpdater {
/**
* Starting an simulated update process of an simulated device.
*
*
* @param tenant
* the tenant of the device
* @param id
@@ -61,12 +62,13 @@ public class DeviceSimulatorUpdater {
device.setProgress(0.0);
device.setSwversion(swVersion);
eventbus.post(new InitUpdate(device));
threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback),
2000, TimeUnit.MILLISECONDS);
2_000, TimeUnit.MILLISECONDS);
}
private static final class DeviceSimulatorUpdateThread implements Runnable {
private static final Random rndSleep = new Random();
private static final Random rndSleep = new SecureRandom();
private final AbstractSimulatedDevice device;
private final SpSenderService spSenderService;
@@ -74,9 +76,8 @@ public class DeviceSimulatorUpdater {
private final EventBus eventbus;
private final UpdaterCallback callback;
private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device,
final SpSenderService spSenderService, final long actionId, final EventBus eventbus,
final UpdaterCallback callback) {
private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService,
final long actionId, final EventBus eventbus, final UpdaterCallback callback) {
this.device = device;
this.spSenderService = spSenderService;
this.actionId = actionId;
@@ -89,8 +90,9 @@ public class DeviceSimulatorUpdater {
final double newProgress = device.getProgress() + 0.2;
device.setProgress(newProgress);
if (newProgress < 1.0) {
threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus,
callback), rndSleep.nextInt(3000), TimeUnit.MILLISECONDS);
threadPool.schedule(
new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback),
rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS);
} else {
callback.updateFinished(device, actionId);
}
@@ -102,7 +104,7 @@ public class DeviceSimulatorUpdater {
* Callback interface which is called when the simulated update process has
* been finished and the caller of starting the simulated update process can
* send the result to the hawkbit update server back.
*
*
* @author Michael Hirsch
*
*/
@@ -111,7 +113,7 @@ public class DeviceSimulatorUpdater {
/**
* Callback method to indicate that the simulated update process has
* been finished.
*
*
* @param device
* the device which has been updated
* @param actionId

View File

@@ -16,6 +16,8 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -24,13 +26,15 @@ import com.google.common.eventbus.EventBus;
/**
* Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every
* second.
*
*
* @author Michael Hirsch
*
*/
@Component
public class NextPollTimeController {
private static final Logger LOGGER = LoggerFactory.getLogger(NextPollTimeController.class);
private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
private static final ExecutorService pollService = Executors.newFixedThreadPool(1);
@@ -58,14 +62,9 @@ public class NextPollTimeController {
if (nextCounter < 0) {
if (device instanceof DDISimulatedDevice) {
try {
pollService.submit(new Runnable() {
@Override
public void run() {
((DDISimulatedDevice) device).poll();
}
});
} catch (final Exception e) {
pollService.submit(() -> ((DDISimulatedDevice) device).poll());
} catch (final IllegalStateException e) {
LOGGER.trace("Device could not be polled", e);
}
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
}

View File

@@ -8,9 +8,13 @@
*/
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@@ -42,19 +46,49 @@ public class SimulationController {
* the amount of devices to be created
* @param tenant
* the tenant to create the device to
* @param api
* the api-protocol to be used either {@code dmf} or {@code ddi}
* @param endpoint
* the URL endpoint to be used of the hawkbit-update-server for
* DDI devices
* @param pollDelay
* number of delay in milliseconds to delay polling of DDI
* devices
* @param gatewayToken
* the hawkbit-update-server gatwaytoken in case authentication
* is enforced in hawkbit
* @return a response string that devices has been created
* @throws MalformedURLException
*/
@RequestMapping("/start")
String start(@RequestParam(value = "name", defaultValue = "dmfSimulated") final String name,
ResponseEntity<String> start(@RequestParam(value = "name", defaultValue = "simulated") final String name,
@RequestParam(value = "amount", defaultValue = "20") final int amount,
@RequestParam(value = "tenant", defaultValue = "DEFAULT") final String tenant) {
@RequestParam(value = "tenant", defaultValue = "DEFAULT") final String tenant,
@RequestParam(value = "api", defaultValue = "dmf") final String api,
@RequestParam(value = "endpoint", defaultValue = "http://localhost:8080") final String endpoint,
@RequestParam(value = "polldelay", defaultValue = "30") final int pollDelay,
@RequestParam(value = "gatewaytoken", defaultValue = "") final String gatewayToken)
throws MalformedURLException {
final Protocol protocol;
switch (api.toLowerCase()) {
case "dmf":
protocol = Protocol.DMF_AMQP;
break;
case "ddi":
protocol = Protocol.DDI_HTTP;
break;
default:
return ResponseEntity.badRequest().body("query param api only allows value of 'dmf' or 'ddi'");
}
for (int i = 0; i < amount; i++) {
final String deviceId = name + i;
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, Protocol.DMF_AMQP));
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint),
gatewayToken));
spSenderService.createOrUpdateThing(tenant, deviceId);
}
return "Updated " + amount + " DMF connected targets!";
return ResponseEntity.ok("Updated " + amount + " DMF connected targets!");
}
}

View File

@@ -9,21 +9,35 @@
package org.eclipse.hawkbit.simulator.amqp;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Bean which holds the necessary properties for configuring the AMQP
* connection.
*
*
*
*/
@Component
@ConfigurationProperties("hawkbit.device.simulator.amqp")
public class AmqpProperties {
/**
* Queue for receiving DMF messages from update server.
*/
private String receiverConnectorQueueFromSp;
/**
* Exchange for sending DMF messages to update server.
*/
private String senderForSpExchange;
/**
* Simulator dead letter queue.
*/
private String deadLetterQueue;
/**
* Simulator dead letter exchange.
*/
private String deadLetterExchange;
public String getReceiverConnectorQueueFromSp() {

View File

@@ -13,11 +13,8 @@ import java.util.Map;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.ActionStatus;
import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater.UpdaterCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
@@ -139,31 +136,22 @@ public class SpReceiverService extends ReceiverService {
DownloadAndUpdateRequest.class);
final Long actionId = downloadAndUpdateRequest.getActionId();
try {
Thread.sleep(1_000);
} catch (final InterruptedException e) {
LOGGER.error("Sleep interrupted", e);
}
spSenderService.sendActionStatusMessage(tenant, ActionStatus.RUNNING,
"device Simulator retrieved update request. proceeding with simulation.", actionId);
deviceUpdater.startUpdate(tenant, thingId, actionId, downloadAndUpdateRequest.getSoftwareModules().get(0)
.getModuleVersion(), new UpdaterCallback() {
@Override
public void updateFinished(final AbstractSimulatedDevice device, final Long actionId) {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
spSenderService.finishUpdateProcess(new SimulatedUpdate(device.getTenant(), device.getId(),
actionId), "Simulation complete!");
break;
case ERROR:
spSenderService.finishUpdateProcessWithError(new SimulatedUpdate(device.getTenant(),
device.getId(), actionId), "Simulation complete with error!");
break;
default:
break;
}
}
});
deviceUpdater.startUpdate(tenant, thingId, actionId,
downloadAndUpdateRequest.getSoftwareModules().get(0).getModuleVersion(), (device, actionId1) -> {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
spSenderService.finishUpdateProcess(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete!");
break;
case ERROR:
spSenderService.finishUpdateProcessWithError(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete with error!");
break;
default:
break;
}
});
}
}

View File

@@ -15,16 +15,15 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.Property;
import com.vaadin.data.Validator;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.validator.NullValidator;
import com.vaadin.data.validator.RangeValidator;
import com.vaadin.data.validator.RegexpValidator;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.Resource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.TextField;
@@ -44,6 +43,15 @@ public class GenerateDialog extends Window {
private final FormLayout formLayout = new FormLayout();
private final TextField namePrefixTextField;
private final TextField amountTextField;
private final TextField tenantTextField;
private final TextField pollDelayTextField;
private final TextField pollUrlTextField;
private final TextField gatewayTokenTextField;
private final OptionGroup protocolGroup;
private final Button buttonOk;
/**
* Creates a new pop window for setting the configuration of simulating
* devices.
@@ -57,97 +65,43 @@ public class GenerateDialog extends Window {
formLayout.setSpacing(true);
formLayout.setMargin(true);
final TextField tf1 = new TextField("name prefix", "dmfSimulated");
tf1.setIcon(FontAwesome.INFO);
tf1.setRequired(true);
tf1.addValidator(new NullValidator("Must be given", false));
namePrefixTextField = createRequiredTextfield("name prefix", "dmfSimulated", FontAwesome.INFO,
new NullValidator("Must be given", false));
final TextField tf2 = new TextField("amount", new ObjectProperty<Integer>(10));
tf2.setIcon(FontAwesome.GEAR);
tf2.setRequired(true);
tf2.addValidator(new RangeValidator<Integer>("Must be between 1 and 30000", Integer.class, 1, 30000));
amountTextField = createRequiredTextfield("amount", new ObjectProperty<Integer>(10), FontAwesome.GEAR,
new RangeValidator<Integer>("Must be between 1 and 30000", Integer.class, 1, 30000));
final TextField tf3 = new TextField("tenant", "default");
tf3.setIcon(FontAwesome.USER);
tf3.setRequired(true);
tf3.addValidator(new NullValidator("Must be given", false));
tenantTextField = createRequiredTextfield("tenant", "default", FontAwesome.USER,
new NullValidator("Must be given", false));
final TextField tf4 = new TextField("poll delay (sec)", new ObjectProperty<Integer>(10));
tf4.setIcon(FontAwesome.CLOCK_O);
tf4.setRequired(true);
tf4.setVisible(false);
tf4.addValidator(new RangeValidator<Integer>("Must be between 1 and 60", Integer.class, 1, 60));
pollDelayTextField = createRequiredTextfield("poll delay (sec)", new ObjectProperty<Integer>(10),
FontAwesome.CLOCK_O, new RangeValidator<Integer>("Must be between 1 and 60", Integer.class, 1, 60));
pollDelayTextField.setVisible(false);
final TextField tf5 = new TextField("base poll URL endpoint", "http://localhost:8080");
tf5.setColumns(50);
tf5.setIcon(FontAwesome.FLAG_O);
tf5.setRequired(true);
tf5.setVisible(false);
tf5.addValidator(new RegexpValidator(
"^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]", "is not an URL"));
pollUrlTextField = createRequiredTextfield("base poll URL endpoint", "http://localhost:8080",
FontAwesome.FLAG_O, new RegexpValidator(
"^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]", "is not an URL"));
pollUrlTextField.setColumns(50);
pollUrlTextField.setVisible(false);
final TextField tf6 = new TextField("gateway token", "");
tf6.setColumns(50);
tf6.setIcon(FontAwesome.FLAG_O);
tf6.setRequired(true);
tf6.setVisible(false);
gatewayTokenTextField = createRequiredTextfield("gateway token", "", FontAwesome.FLAG_O, null);
gatewayTokenTextField.setColumns(50);
gatewayTokenTextField.setVisible(false);
final OptionGroup protocolGroup = new OptionGroup("Simulated Device Protocol");
protocolGroup.addItem(Protocol.DMF_AMQP);
protocolGroup.addItem(Protocol.DDI_HTTP);
protocolGroup.setItemCaption(Protocol.DMF_AMQP, "Device Management Federation API (AMQP push)");
protocolGroup.setItemCaption(Protocol.DDI_HTTP, "Direct Device Interface (HTTP poll)");
protocolGroup.setNullSelectionAllowed(false);
protocolGroup.select(Protocol.DMF_AMQP);
protocolGroup.addValueChangeListener(new ValueChangeListener() {
private static final long serialVersionUID = 1L;
protocolGroup = createProtocolGroup();
buttonOk = createOkButton(callback);
@Override
public void valueChange(final ValueChangeEvent event) {
if (event.getProperty().getValue().equals(Protocol.DDI_HTTP)) {
tf4.setVisible(true);
tf5.setVisible(true);
tf6.setVisible(true);
} else {
tf4.setVisible(false);
tf5.setVisible(false);
tf6.setVisible(false);
}
}
});
namePrefixTextField.addValueChangeListener(event -> checkValid());
amountTextField.addValueChangeListener(event -> checkValid());
tenantTextField.addValueChangeListener(event -> checkValid());
final Button buttonOk = new Button("generate");
buttonOk.setImmediate(true);
buttonOk.setIcon(FontAwesome.GEARS);
buttonOk.addClickListener(new ClickListener() {
private static final long serialVersionUID = 1L;
@Override
public void buttonClick(final ClickEvent event) {
try {
callback.okButton(tf1.getValue(), tf3.getValue(), Integer.valueOf(tf2.getValue().replace(".", "")),
Integer.valueOf(tf4.getValue().replace(".", "")), new URL(tf5.getValue()), tf6.getValue(),
(Protocol) protocolGroup.getValue());
} catch (final NumberFormatException e) {
LOGGER.info(e.getMessage(), e);
} catch (final MalformedURLException e) {
LOGGER.info(e.getMessage(), e);
}
GenerateDialog.this.close();
}
});
tf1.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
tf2.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
tf3.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
formLayout.addComponent(tf1);
formLayout.addComponent(tf2);
formLayout.addComponent(tf3);
formLayout.addComponent(namePrefixTextField);
formLayout.addComponent(amountTextField);
formLayout.addComponent(tenantTextField);
formLayout.addComponent(protocolGroup);
formLayout.addComponent(tf4);
formLayout.addComponent(tf5);
formLayout.addComponent(tf6);
formLayout.addComponent(pollDelayTextField);
formLayout.addComponent(pollUrlTextField);
formLayout.addComponent(gatewayTokenTextField);
formLayout.addComponent(buttonOk);
setCaption("Simulate Devices");
@@ -156,13 +110,10 @@ public class GenerateDialog extends Window {
center();
}
private void checkValid(final TextField tf1, final TextField tf2, final TextField tf3, final TextField tf4,
final Button buttonOk) {
if (tf1.isValid() && tf2.isValid() && tf3.isValid() && tf4.isValid()) {
buttonOk.setEnabled(true);
} else {
buttonOk.setEnabled(false);
}
private void checkValid() {
buttonOk.setEnabled(namePrefixTextField.isValid() && amountTextField.isValid() && tenantTextField.isValid()
&& pollDelayTextField.isValid());
}
@Override
@@ -230,4 +181,66 @@ public class GenerateDialog extends Window {
void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay,
final URL basePollURL, final String gatewayToken, final Protocol protocol);
}
private OptionGroup createProtocolGroup() {
final OptionGroup protocolGroup = new OptionGroup("Simulated Device Protocol");
protocolGroup.addItem(Protocol.DMF_AMQP);
protocolGroup.addItem(Protocol.DDI_HTTP);
protocolGroup.setItemCaption(Protocol.DMF_AMQP, "Device Management Federation API (AMQP push)");
protocolGroup.setItemCaption(Protocol.DDI_HTTP, "Direct Device Interface (HTTP poll)");
protocolGroup.setNullSelectionAllowed(false);
protocolGroup.select(Protocol.DMF_AMQP);
protocolGroup.addValueChangeListener(event -> {
final boolean directDeviceOptionSelected = event.getProperty().getValue().equals(Protocol.DDI_HTTP);
pollDelayTextField.setVisible(directDeviceOptionSelected);
pollUrlTextField.setVisible(directDeviceOptionSelected);
gatewayTokenTextField.setVisible(directDeviceOptionSelected);
});
return protocolGroup;
}
private Button createOkButton(final GenerateDialogCallback callback) {
final Button buttonOk = new Button("generate");
buttonOk.setImmediate(true);
buttonOk.setIcon(FontAwesome.GEARS);
buttonOk.addClickListener(event -> {
try {
callback.okButton(namePrefixTextField.getValue(), tenantTextField.getValue(),
Integer.valueOf(amountTextField.getValue().replace(".", "").replace(",", "")),
Integer.valueOf(pollDelayTextField.getValue().replace(".", "")),
new URL(pollUrlTextField.getValue()), gatewayTokenTextField.getValue(),
(Protocol) protocolGroup.getValue());
} catch (final NumberFormatException e) {
LOGGER.info(e.getMessage(), e);
} catch (final MalformedURLException e) {
LOGGER.info(e.getMessage(), e);
}
GenerateDialog.this.close();
});
return buttonOk;
}
private TextField createRequiredTextfield(final String caption, final String value, final Resource icon,
final Validator validator) {
final TextField textField = new TextField(caption, value);
return addTextFieldValues(textField, icon, validator);
}
private TextField createRequiredTextfield(final String caption, final Property dataSource, final Resource icon,
final Validator validator) {
final TextField textField = new TextField(caption, dataSource);
return addTextFieldValues(textField, icon, validator);
}
private TextField addTextFieldValues(final TextField textField, final Resource icon, final Validator validator) {
textField.setIcon(icon);
textField.setRequired(true);
if (validator != null) {
textField.addValidator(validator);
}
return textField;
}
}

View File

@@ -28,8 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.converter.Converter;
@@ -76,8 +74,8 @@ public class SimulatorView extends VerticalLayout implements View {
private final Label caption = new Label("DMF/DDI Simulated Devices");
private final HorizontalLayout toolbar = new HorizontalLayout();
private final Grid grid = new Grid();
private final ComboBox responseComboBox = new ComboBox("", Lists.newArrayList(ResponseStatus.SUCCESSFUL,
ResponseStatus.ERROR));
private final ComboBox responseComboBox = new ComboBox("",
Lists.newArrayList(ResponseStatus.SUCCESSFUL, ResponseStatus.ERROR));
private BeanContainer<String, AbstractSimulatedDevice> beanContainer;
@@ -97,6 +95,9 @@ public class SimulatorView extends VerticalLayout implements View {
grid.setSizeFull();
grid.setCellStyleGenerator(new CellStyleGenerator() {
private static final long serialVersionUID = 1L;
@Override
public String getStyle(final CellReference cellReference) {
return cellReference.getPropertyId().equals("status") ? "centeralign" : null;
@@ -118,86 +119,8 @@ public class SimulatorView extends VerticalLayout implements View {
grid.getColumn("swversion").setHeaderCaption("SW Version");
grid.getColumn("responseStatus").setHeaderCaption("Response Update Status");
grid.getColumn("progress").setRenderer(new ProgressBarRenderer());
grid.getColumn("protocol").setConverter(new Converter<String, Protocol>() {
@Override
public Protocol convertToModel(final String value, final Class<? extends Protocol> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Protocol value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case DDI_HTTP:
return "DDI API (http)";
case DMF_AMQP:
return "DMF API (amqp)";
default:
return "unknown";
}
}
@Override
public Class<Protocol> getModelType() {
return Protocol.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
});
grid.getColumn("status").setRenderer(new HtmlRenderer(), new Converter<String, Status>() {
private static final long serialVersionUID = 1L;
@Override
public Status convertToModel(final String value, final Class<? extends Status> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Status value, final Class<? extends String> targetType,
final Locale locale) {
String style = null;
switch (value) {
case UNKNWON:
style = "<span class=\"v-icon grayicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"gray\";\">&#x"
+ Integer.toHexString(FontAwesome.QUESTION_CIRCLE.getCodepoint()) + ";</span>";
break;
case PEDNING:
style = "<span class=\"v-icon yellowicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"yellow\";\">&#x" + Integer.toHexString(FontAwesome.REFRESH.getCodepoint())
+ ";</span>";
break;
case FINISH:
style = "<span class=\"v-icon greenicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"green\";\">&#x"
+ Integer.toHexString(FontAwesome.CHECK_CIRCLE.getCodepoint()) + ";</span>";
break;
case ERROR:
style = "<span class=\"v-icon redicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"red\";\">&#x"
+ Integer.toHexString(FontAwesome.EXCLAMATION_CIRCLE.getCodepoint()) + ";</span>";
break;
default:
throw new IllegalStateException("unknown value");
}
return style;
}
@Override
public Class<Status> getModelType() {
return Status.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
});
grid.getColumn("protocol").setConverter(createProtocolConverter());
grid.getColumn("status").setRenderer(new HtmlRenderer(), createStatusConverter());
grid.removeColumn("tenant");
// grid combobox
@@ -205,13 +128,9 @@ public class SimulatorView extends VerticalLayout implements View {
responseComboBox.setItemIcon(ResponseStatus.ERROR, FontAwesome.EXCLAMATION_CIRCLE);
responseComboBox.setNullSelectionAllowed(false);
responseComboBox.setValue(ResponseStatus.SUCCESSFUL);
responseComboBox.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange(final ValueChangeEvent event) {
beanContainer.getItemIds().forEach(
itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus")
.setValue(event.getProperty().getValue()));
}
responseComboBox.addValueChangeListener(valueChangeEvent -> {
beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus")
.setValue(valueChangeEvent.getProperty().getValue()));
});
// add all components
@@ -338,4 +257,90 @@ public class SimulatorView extends VerticalLayout implements View {
}
}));
}
private Converter<String, Protocol> createProtocolConverter() {
return new Converter<String, Protocol>() {
private static final long serialVersionUID = 1L;
@Override
public Protocol convertToModel(final String value, final Class<? extends Protocol> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Protocol value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case DDI_HTTP:
return "DDI API (http)";
case DMF_AMQP:
return "DMF API (amqp)";
default:
return "unknown";
}
}
@Override
public Class<Protocol> getModelType() {
return Protocol.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
};
}
private Converter<String, Status> createStatusConverter() {
return new Converter<String, Status>() {
private static final long serialVersionUID = 1L;
@Override
public Status convertToModel(final String value, final Class<? extends Status> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Status value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case UNKNWON:
return "<span class=\"v-icon grayicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"gray\";\">&#x"
+ Integer.toHexString(FontAwesome.QUESTION_CIRCLE.getCodepoint()) + ";</span>";
case PEDNING:
return "<span class=\"v-icon yellowicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"yellow\";\">&#x" + Integer.toHexString(FontAwesome.REFRESH.getCodepoint())
+ ";</span>";
case FINISH:
return "<span class=\"v-icon greenicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"green\";\">&#x"
+ Integer.toHexString(FontAwesome.CHECK_CIRCLE.getCodepoint()) + ";</span>";
case ERROR:
return "<span class=\"v-icon redicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"red\";\">&#x"
+ Integer.toHexString(FontAwesome.EXCLAMATION_CIRCLE.getCodepoint()) + ";</span>";
default:
throw new IllegalStateException("unknown value");
}
}
@Override
public Class<Status> getModelType() {
return Status.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
};
}
}

View File

@@ -0,0 +1,28 @@
#
# 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
#
# SECURITY (SecurityProperties)
security.basic.enabled=true
security.user.name=${BASIC_USERNAME:admin}
security.user.password=${BASIC_PASSWORD:admin}
security.user.role=USER
security.require-ssl=false
security.enable-csrf=false
security.basic.enabled=true
security.basic.realm=DeviceSimulator
security.basic.path= /**
security.basic.authorize-mode=ROLE
security.filter-order=0
security.headers.xss=false
security.headers.cache=false
security.headers.frame=false
security.headers.content-type=false
security.headers.hsts=all
security.sessions=stateless
security.ignored=/VAADIN/**

View File

@@ -27,23 +27,5 @@ spring.rabbitmq.port=5672
spring.rabbitmq.dynamic=true
spring.rabbitmq.listener.prefetch=100
# SECURITY (SecurityProperties)
security.user.name=${BASIC_USERNAME:admin}
security.user.password=${BASIC_PASSWORD:admin}
security.user.role=USER
security.require-ssl=false
security.enable-csrf=false
security.basic.enabled=true
security.basic.realm=DeviceSimulator
security.basic.path= /**
security.basic.authorize-mode=ROLE
security.filter-order=0
security.headers.xss=false
security.headers.cache=false
security.headers.frame=false
security.headers.content-type=false
security.headers.hsts=all
security.sessions=stateless
security.ignored=/VAADIN/**
security.basic.enabled=false
server.port=8083

View File

@@ -8,21 +8,12 @@
*/
package org.eclipse.hawkbit.app;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.eventbus.event.EntityEvent;
import org.eclipse.hawkbit.ui.DispatcherRunnable;
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.vaadin.spring.events.EventBus.SessionEventBus;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
import com.google.common.eventbus.EventBus;
import com.vaadin.annotations.Push;
import com.vaadin.server.VaadinSession;
import com.vaadin.server.VaadinSession.State;
import com.vaadin.server.WrappedSession;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.Transport;
import com.vaadin.spring.annotation.SpringUI;
@@ -33,45 +24,16 @@ import com.vaadin.spring.annotation.SpringUI;
* 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)
@EventSubscriber
public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
/**
* An {@link com.google.common.eventbus.EventBus} subscriber which
* subscribes {@link EntityEvent} from the repository to dispatch these
* events to the UI {@link SessionEventBus}.
*
* @param event
* the entity event which has been published from the repository
*/
@Override
@Subscribe
@AllowConcurrentEvents
public void dispatch(final org.eclipse.hawkbit.eventbus.event.Event event) {
final VaadinSession session = getSession();
if (session != null && session.getState() == State.OPEN) {
final WrappedSession wrappedSession = session.getSession();
if (wrappedSession != null) {
final SecurityContext userContext = (SecurityContext) wrappedSession
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
if (eventSecurityCheck(userContext, event)) {
final SecurityContext oldContext = SecurityContextHolder.getContext();
try {
access(new DispatcherRunnable(eventBus, session, userContext, event));
} finally {
SecurityContextHolder.setContext(oldContext);
}
}
}
}
@Autowired
public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus) {
super(new DelayedEventBusPushStrategy(eventBus, systemEventBus));
}
}

View File

@@ -7,23 +7,35 @@
# http://www.eclipse.org/legal/epl-v10.html
#
# need to re-name these properties in the defaulthawkbit.properties and code!
hawkbit.server.controller.security.authentication.anonymous.enabled=true
hawkbit.server.controller.security.authentication.header.enabled=false
hawkbit.server.controller.security.authentication.targettoken.enabled=false
hawkbit.server.controller.security.authentication.gatewaytoken.enabled=false
hawkbit.server.ddi.security.authentication.anonymous.enabled=true
hawkbit.server.ddi.security.authentication.targettoken.enabled=false
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false
spring.profiles.active=amqp
vaadin.servlet.params.productionMode=false
vaadin.static.servlet.params.productionMode=false
vaadin.servlet.productionMode=false
## Configuration for RabbitMQ integration
hawkbit.server.amqp.username=guest
hawkbit.server.amqp.password=guest
hawkbit.server.amqp.virtualHost=/
hawkbit.server.amqp.host=localhost
hawkbit.server.amqp.port=5672
hawkbit.server.amqp.deadLetterQueue=sp_deadletter
hawkbit.server.amqp.deadLetterExchange=sp.deadletter
hawkbit.server.amqp.receiverQueue=sp_receiver
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtualHost=/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
# 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
hawkbit.server.ui.links.documentation.deployment-view=https://github.com/eclipse/hawkbit
hawkbit.server.ui.links.documentation.distribution-view=https://github.com/eclipse/hawkbit
hawkbit.server.ui.links.documentation.rollout-view=https://github.com/eclipse/hawkbit
hawkbit.server.ui.links.documentation.security=https://github.com/eclipse/hawkbit
hawkbit.server.ui.links.documentation.system-configuration-view=https://github.com/eclipse/hawkbit
hawkbit.server.ui.links.documentation.targetfilter-view=https://github.com/eclipse/hawkbit
hawkbit.server.ui.links.documentation.upload-view=https://github.com/eclipse/hawkbit

View File

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

View File

@@ -1,3 +1,39 @@
# HawkBit management API example
Example client that shows how to efficiently use the hawkBit management API.
Powered by [Feign](https://github.com/Netflix/feign).
Powered by [Feign](https://github.com/Netflix/feign).
## How to run the example client
Run getting started example
$ java -jar hawkbit-mgmt-api-client-#version#.jar
Run create and start rollout example
$ java -jar hawkbit-mgmt-api-client-#version#.jar --createrollout
## This example shows
In getting started example:
* creating software modules type
* creating distribution set type
* creating distribution sets
* creating software modules
* assigning software modules to distribution sets
In rollout mode:
* creating software modules type
* creating distribution set type
* creating distribution sets
* creating software modules
* assigning software modules to distribution sets
* creating a rollout
* starting a rollout

View File

@@ -16,9 +16,43 @@
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<artifactId>hawkbit-mgmt-api-client</artifactId>
<name>hawkBit Management API example client</name>
<build>
<plugins>
<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.mgmt.client.Application</mainClass>
<layout>JAR</layout>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<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>
@@ -26,45 +60,37 @@
<artifactId>hawkbit-rest-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.12.1</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.12.1</version>
<!-- need to overwrite for the interface inheritance feature of feign-core -->
<version>8.14.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-example-app</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate</groupId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0-rc2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -1,38 +0,0 @@
/**
* 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.api.client;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.RestConstants;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest;
import feign.Headers;
import feign.RequestLine;
/**
* Client binding for the Distribution resource of the management API.
*/
@FunctionalInterface
public interface DistributionSetResource {
/**
* Creates a list of distribution sets.
*
* @param sets
* the request body java bean containing the necessary attributes
* for creating a distribution set.
* @return the list of targets which have been created
*/
@RequestLine("POST " + RestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)
@Headers("Content-Type: application/json")
DistributionSetsRest createDistributionSets(final List<DistributionSetRequestBodyPost> sets);
}

View File

@@ -1,138 +0,0 @@
/**
* 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.api.client;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.RestConstants;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest;
import org.eclipse.hawkbit.rest.resource.model.tag.AssignedDistributionSetRequestBody;
import org.eclipse.hawkbit.rest.resource.model.tag.DistributionSetTagAssigmentResultRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TagsRest;
import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
/**
* Client binding for the DistributionSetTag resource of the management API.
*/
public interface DistrubutionSetTagResource {
/**
* Retrieves a single distributionset tag based on the given ID.
*
* @param dsTagId
* the ID of the distributionset tag to retrieve
* @return a deserialized java bean containing the attributes of the
* returned distributionset tag
*/
@RequestLine("GET " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{dsTagId}")
TagRest getDistributionSetTag(@Param("dsTagId") Long dsTagId);
/**
* Creates a list of distributionset tags.
*
* @param tags
* the tags to be created
* @return the created tag list
*/
@RequestLine("POST " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
@Headers("Content-Type: application/json")
TagsRest createDistributionSetTags(List<TagRequestBodyPut> tags);
/**
* Update attributes of a distributionset tag.
*
* @param dsTagId
* the distributionset tag id to be updated
* @param tag
* the request body
* @return the updated distributionset tag
*/
@RequestLine("PUT " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{dsTagId}")
@Headers("Content-Type: application/json")
TagRest updateDistributionSetTag(@Param("dsTagId") Long dsTagId, TagRequestBodyPut tag);
/**
* Deletes given distributionset tag on given ID.
*
* @param dsTagId
* to be deleted
*/
@RequestLine("DELETE " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/{dsTagId}")
void deleteDistributionSetTag(@Param("dsTagId") final Long dsTagId);
/**
* Retrieves a all assigned targets on the given distributionset tag id.
*
* @param dsTagId
* the ID of the distributionset tag to retrieve
* @return a list of targets
*/
@RequestLine("GET " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING)
DistributionSetsRest getAssignedDistributionSets(@Param("dsTagId") final Long dsTagId);
/**
* Toggle the tag assignment all assigned targets will be unassigned and all
* unassigned targets will be assigned.
*
* @param dsTagId
* the ID of the distributionset tag to toggle
* @param assignedTargetRequestBodies
* a list of controller ids
* @return a list of assigned and unassigned targets
*/
@RequestLine("POST " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + "/toggleTagAssignment")
@Headers("Content-Type: application/json")
DistributionSetTagAssigmentResultRest toggleTagAssignment(@Param("dsTagId") final Long dsTagId,
final List<AssignedDistributionSetRequestBody> assignedTargetRequestBodies);
/**
* Assign targets to a given distributionset tag id.
*
* @param dsTagId
* the ID of the distributionset tag to add the targets
* @param assignedTargetRequestBodies
* a list of controller ids
* @return a list of assigned targets
*/
@RequestLine("POST " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING)
@Headers("Content-Type: application/json")
TargetsRest assignDistributionSets(@Param("dsTagId") final Long dsTagId,
final List<AssignedDistributionSetRequestBody> assignedTargetRequestBodies);
/**
* Unassign targets to a given distributionset tag id.
*
* @param dsTagId
* the ID of the distributionset tag to add the targets
*/
@RequestLine("DELETE " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING)
void unassignDistributionSets(@Param("dsTagId") final Long dsTagId);
/**
* Unassign one target to a given distributionset tag id.
*
* @param dsTagId
* the ID of the distributionset tag to add the targets param
* @param dsId
* the distributionset id
*/
@RequestLine("DELETE " + RestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ RestConstants.DISTRIBUTIONSET_REQUEST_MAPPING + "/{dsId}")
void unassignDistributionSet(@Param("dsTagId") final Long dsTagId, @Param("dsId") final Long dsId);
}

View File

@@ -1,80 +0,0 @@
/**
* 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.api.client;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.target.TargetPagedList;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRest;
import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
/**
* Client binding for the Target resource of the management API.
*/
public interface TargetResource {
/**
* Retrieves a single target based on the given ID.
*
* @param targetId
* the ID of the target to retrieve
* @return a deserialized java bean containing the attributes of the
* returned target
*/
@RequestLine("GET /rest/v1/targets/{targetId}")
TargetRest getTarget(@Param("targetId") final String targetId);
/**
* Paged query of targets resource.
*
* @param pagingOffsetParam
* of the paged query
* @param pagingLimitParam
* of the paged query
* @return paged list of target entries
*/
@RequestLine("GET /rest/v1/targets?offset={pagingOffsetParam}&limit={pagingLimitParam}")
TargetPagedList getTargets(@Param("pagingOffsetParam") int pagingOffsetParam,
@Param("pagingLimitParam") int pagingLimitParam);
/**
* Paged query of targets resource with default offset and limit.
*
* @return paged list of target entries
*/
@RequestLine("GET /rest/v1/targets")
TargetPagedList getTargets();
/**
* Deletes given target based on given ID.
*
* @param targetId
* to be deleted
*/
@RequestLine("DELETE /rest/v1/targets/{targetId}")
void deleteTarget(@Param("targetId") final String targetId);
/**
* Creates a list of targets.
*
* @param targets
* the request body java bean containing the necessary attributes
* for creating a target.
* @return the list of targets which have been created
*/
@RequestLine("POST /rest/v1/targets/")
@Headers("Content-Type: application/json")
TargetsRest createTargets(List<TargetRequestBody> targets);
}

View File

@@ -1,137 +0,0 @@
/**
* 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.api.client;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.RestConstants;
import org.eclipse.hawkbit.rest.resource.model.tag.AssignedTargetRequestBody;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TagsRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TargetTagAssigmentResultRest;
import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
/**
* Client binding for the Target resource of the management API.
*/
public interface TargetTagResource {
/**
* Retrieves a single target tag based on the given ID.
*
* @param targetTagId
* the ID of the target tag to retrieve
* @return a deserialized java bean containing the attributes of the
* returned target tag
*/
@RequestLine("GET " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}")
TagRest getTargetTag(@Param("targetTagId") Long targetTagId);
/**
* Creates a list of target tags.
*
* @param tags
* the tags to be created
* @return the created tag list
*/
@RequestLine("POST " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING)
@Headers("Content-Type: application/json")
TagsRest createTargetTag(List<TagRequestBodyPut> tags);
/**
* Update attributes of a target tag.
*
* @param targetTagId
* the target tag id to be updated
* @param tag
* the request body
* @return the updated target tag
*/
@RequestLine("PUT " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}")
@Headers("Content-Type: application/json")
TagRest updateTagretTag(@Param("targetTagId") Long targetTagId, TagRequestBodyPut tag);
/**
* Deletes given target tag on given ID.
*
* @param targetTagId
* to be deleted
*/
@RequestLine("DELETE " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/{targetTagId}")
void deleteTargetTag(@Param("targetTagId") final Long targetTagId);
/**
* Retrieves a all assigned targets on the given target tag id.
*
* @param targetTagId
* the ID of the target tag to retrieve
* @return a list of targets
*/
@RequestLine("GET " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING)
TargetsRest getAssignedTargets(@Param("targetTagId") final Long targetTagId);
/**
* Toggle the tag assignment all assigned targets will be unassigned and all
* unassigned targets will be assigned.
*
* @param targetTagId
* the ID of the target tag to toggle
* @param assignedTargetRequestBodies
* a list of controller ids
* @return a list of assigned and unassigned targets
*/
@RequestLine("POST " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/toggleTagAssignment")
@Headers("Content-Type: application/json")
TargetTagAssigmentResultRest toggleTagAssignment(@Param("targetTagId") final Long targetTagId,
final List<AssignedTargetRequestBody> assignedTargetRequestBodies);
/**
* Assign targets to a given target tag id.
*
* @param targetTagId
* the ID of the target tag to add the targets
* @param assignedTargetRequestBodies
* a list of controller ids
* @return a list of assigned targets
*/
@RequestLine("POST " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING)
@Headers("Content-Type: application/json")
TargetsRest assignTargets(@Param("targetTagId") final Long targetTagId,
final List<AssignedTargetRequestBody> assignedTargetRequestBodies);
/**
* Unassign targets to a given target tag id.
*
* @param targetTagId
* the ID of the target tag to add the targets
*/
@RequestLine("DELETE " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING)
void unassignTargets(@Param("targetTagId") final Long targetTagId);
/**
* Unassign one target to a given target tag id.
*
* @param targetTagId
* the ID of the target tag to add the targets param
* @param controllerId
* the controller id
*/
@RequestLine("DELETE " + RestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ RestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING + "/{controllerId}")
void unassignTarget(@Param("targetTagId") final Long targetTagId, @Param("controllerId") final String controllerId);
}

View File

@@ -0,0 +1,77 @@
/**
* 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;
import org.eclipse.hawkbit.mgmt.client.scenarios.CreateStartedRolloutExample;
import org.eclipse.hawkbit.mgmt.client.scenarios.GettingStartedDefaultScenario;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import feign.Contract;
import feign.auth.BasicAuthRequestInterceptor;
@SpringBootApplication
@EnableFeignClients
@EnableConfigurationProperties(ClientConfigurationProperties.class)
public class Application implements CommandLineRunner {
@Autowired
private ClientConfigurationProperties configuration;
@Autowired
private GettingStartedDefaultScenario gettingStarted;
@Autowired
private CreateStartedRolloutExample gettingStartedRolloutScenario;
public static void main(final String[] args) {
new SpringApplicationBuilder().showBanner(false).sources(Application.class).run(args);
}
@Override
public void run(final String... args) throws Exception {
if (containsArg("--createrollout", args)) {
// run the create and start rollout example
gettingStartedRolloutScenario.run();
} else {
// run the getting started scenario which creates a setup of
// distribution set and software modules to be used
gettingStarted.run();
}
}
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(configuration.getUsername(), configuration.getPassword());
}
@Bean
public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() {
return new ApplicationJsonRequestHeaderInterceptor();
}
@Bean
public Contract feignContract() {
return new IgnoreMultipleConsumersProducersSpringMvcContract();
}
private boolean containsArg(final String containsArg, final String... args) {
for (final String arg : args) {
if (arg.equalsIgnoreCase(containsArg)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,28 @@
/**
* 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;
import org.springframework.http.MediaType;
import feign.RequestInterceptor;
import feign.RequestTemplate;
/**
* An feign request interceptor to set the defined {@code Accept} and
* {@code Content-Type} headers for each request to {@code application/json}.
*/
public class ApplicationJsonRequestHeaderInterceptor implements RequestInterceptor {
@Override
public void apply(final RequestTemplate template) {
template.header("Accept", MediaType.APPLICATION_JSON_VALUE);
template.header("Content-Type", MediaType.APPLICATION_JSON_VALUE);
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration bean which holds the configuration of the client e.g. the base
* URL of the hawkbit-server and the credentials to use the RESTful Management
* API.
*/
@ConfigurationProperties(prefix = "hawkbit")
public class ClientConfigurationProperties {
/**
* Update server URI.
*/
private String url = "localhost:8080";
/**
* Update server user name.
*/
private String username = "admin";
/**
* Update server password.
*/
private String password = "admin"; // NOSONAR this password is only used for
// examples
public String getUrl() {
return url;
}
public void setUrl(final String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
}

View File

@@ -0,0 +1,43 @@
/**
* 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;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.feign.support.SpringMvcContract;
import feign.MethodMetadata;
/**
* Own implementation of the {@link SpringMvcContract} which catches the
* {@link IllegalStateException} which occurs due multiple produces and consumes
* values in the request-mapping
* annoation.https://github.com/spring-cloud/spring-cloud-netflix/issues/808
*/
public class IgnoreMultipleConsumersProducersSpringMvcContract extends SpringMvcContract {
private static final Logger LOGGER = LoggerFactory
.getLogger(IgnoreMultipleConsumersProducersSpringMvcContract.class);
@Override
protected void processAnnotationOnMethod(final MethodMetadata data, final Annotation methodAnnotation,
final Method method) {
try {
super.processAnnotationOnMethod(data, methodAnnotation, method);
} catch (final IllegalStateException e) {
// ignore illegalstateexception here because it's thrown because of
// multiple consumers and produces, see
// https://github.com/spring-cloud/spring-cloud-netflix/issues/808
LOGGER.trace(e.getMessage(), e);
}
}
}

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
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.DistributionSetRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the DistributionSet resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsets")
public interface DistributionSetResourceClient extends DistributionSetRestApi {
}

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

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.rest.resource.api.DistributionSetTypeRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the DistributionSetType resource of the management API.
*
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/distributionsettypes")
public interface DistributionSetTypeResourceClient extends DistributionSetTypeRestApi {
}

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
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.RolloutRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the Rollout resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/rollouts")
public interface RolloutResourceClient extends RolloutRestApi {
}

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
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleRestAPI;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the SoftwareModule resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/softwaremodules")
public interface SoftwareModuleResourceClient extends SoftwareModuleRestAPI {
}

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
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.SoftwareModuleTypeRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the oftwareModuleType resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/softwaremoduletypes")
public interface SoftwareModuleTypeResourceClient extends SoftwareModuleTypeRestApi {
}

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
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.TargetRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the Target resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targets")
public interface TargetResourceClient extends TargetRestApi {
}

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
*/
package org.eclipse.hawkbit.mgmt.client.resource;
import org.eclipse.hawkbit.rest.resource.api.TargetTagRestApi;
import org.springframework.cloud.netflix.feign.FeignClient;
/**
* Client binding for the TargetTag resource of the management API.
*/
@FeignClient(url = "${hawkbit.endpoint.url:localhost:8080}/rest/v1/targettags")
public interface TargetTagResourceClient extends TargetTagRestApi {
}

View File

@@ -0,0 +1,99 @@
/**
* 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.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link DistributionSetRequestBodyPost}.
*
* @author Jonathan Knoblauch
*
*/
public class DistributionSetBuilder {
private String name;
private String version;
private String type;
/**
* @param name
* the name of the distribution set
* @return the builder itself
*/
public DistributionSetBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param version
* the version of the distribution set
* @return the builder itself
*/
public DistributionSetBuilder version(final String version) {
this.version = version;
return this;
}
/**
* @param type
* the distribution set type name for this distribution set
* @return the builder itself
*/
public DistributionSetBuilder type(final String type) {
this.type = type;
return this;
}
/**
* Builds a list with a single entry of
* {@link DistributionSetRequestBodyPost} which can directly be used to post
* on the RESTful-API.
*
* @return a single entry list of {@link DistributionSetRequestBodyPost}
*/
public List<DistributionSetRequestBodyPost> build() {
return Lists.newArrayList(doBuild(name));
}
/**
* Builds a list of multiple {@link DistributionSetRequestBodyPost} to
* create multiple distribution sets at once. An increasing number will be
* added to the name of the distribution set. The version and type will
* remain the same.
*
* @param count
* the amount of distribution sets body which should be created
* @return a list of {@link DistributionSetRequestBodyPost}
*/
public List<DistributionSetRequestBodyPost> buildAsList(final int count) {
final ArrayList<DistributionSetRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index));
}
return bodyList;
}
private DistributionSetRequestBodyPost doBuild(final String prefixName) {
final DistributionSetRequestBodyPost body = new DistributionSetRequestBodyPost();
body.setName(prefixName);
body.setVersion(version);
body.setType(type);
return body;
}
}

View File

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

View File

@@ -0,0 +1,115 @@
/**
* 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.builder;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutCondition;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutCondition.Condition;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody;
/**
*
* Builder pattern for building {@link RolloutRestRequestBody}.
*
* @author Jonathan Knoblauch
*
*/
public class RolloutBuilder {
private String name;
private int groupSize;
private String targetFilterQuery;
private long distributionSetId;
private String successThreshold;
private String errorThreshold;
/**
* @param name
* the name of the rollout
* @return the builder itself
*/
public RolloutBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param groupSize
* the amount of groups the rollout should be split into
* @return the builder itself
*/
public RolloutBuilder groupSize(final int groupSize) {
this.groupSize = groupSize;
return this;
}
/**
* @param targetFilterQuery
* the FIQL query language to filter targets to contain in the
* rollout
* @return the builder itself
*/
public RolloutBuilder targetFilterQuery(final String targetFilterQuery) {
this.targetFilterQuery = targetFilterQuery;
return this;
}
/**
* @param distributionSetId
* the ID of the distribution set to assign to the target in the
* rollout
* @return the builder itself
*/
public RolloutBuilder distributionSetId(final long distributionSetId) {
this.distributionSetId = distributionSetId;
return this;
}
/**
* @param successThreshold
* the threshold to be used to indicate if a deployment group is
* successful, to trigger the success action
* @return the builder itself
*/
public RolloutBuilder successThreshold(final String successThreshold) {
this.successThreshold = successThreshold;
return this;
}
/**
* @param errorThreshold
* the threshold to be used to indicate if a deployment group is
* failing, to trigger the error action
* @return the builder itself
*/
public RolloutBuilder errorThreshold(final String errorThreshold) {
this.errorThreshold = errorThreshold;
return this;
}
/**
* Builds the rollout rest body to creating a rollout.
*
* @return the rest request body for creating a rollout
*/
public RolloutRestRequestBody build() {
return doBuild();
}
private RolloutRestRequestBody doBuild() {
final RolloutRestRequestBody body = new RolloutRestRequestBody();
body.setName(name);
body.setAmountGroups(groupSize);
body.setTargetFilterQuery(targetFilterQuery);
body.setDistributionSetId(distributionSetId);
body.setSuccessCondition(new RolloutCondition(Condition.THRESHOLD, successThreshold));
body.setErrorCondition(new RolloutCondition(Condition.THRESHOLD, errorThreshold));
return body;
}
}

View File

@@ -0,0 +1,57 @@
/**
* 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.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleAssigmentRest;
/**
*
* Builder pattern for building {@link SoftwareModuleAssigmentRest}.
*
* @author Jonathan Knoblauch
*
*/
public class SoftwareModuleAssigmentBuilder {
private final List<Long> ids;
public SoftwareModuleAssigmentBuilder() {
ids = new ArrayList<>();
}
/**
* @param id
* the id of the software module
* @return the builder itself
*/
public SoftwareModuleAssigmentBuilder id(final Long id) {
ids.add(id);
return this;
}
/**
* Builds a list with a single entry of {@link SoftwareModuleAssigmentRest}
* which can directly be used in the RESTful-API.
*
* @return a single entry list of {@link SoftwareModuleAssigmentRest}
*/
public List<SoftwareModuleAssigmentRest> build() {
final List<SoftwareModuleAssigmentRest> softwareModuleAssigmentRestList = new ArrayList<>();
for (final Long id : ids) {
final SoftwareModuleAssigmentRest softwareModuleAssigmentRest = new SoftwareModuleAssigmentRest();
softwareModuleAssigmentRest.setId(id);
softwareModuleAssigmentRestList.add(softwareModuleAssigmentRest);
}
return softwareModuleAssigmentRestList;
}
}

View File

@@ -0,0 +1,101 @@
/**
* 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.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link SoftwareModuleRequestBodyPost}.
*
* @author Jonathan Knoblauch
*
*/
public class SoftwareModuleBuilder {
private String name;
private String version;
private String type;
/**
* @param name
* the name of the software module
* @return the builder itself
*/
public SoftwareModuleBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param version
* the version of the software module
* @return the builder itsefl
*/
public SoftwareModuleBuilder version(final String version) {
this.version = version;
return this;
}
/**
* @param type
* the key of the software module type to be used for this
* software module
* @return the builder itself
*/
public SoftwareModuleBuilder type(final String type) {
this.type = type;
return this;
}
/**
* Builds a list with a single entry of
* {@link SoftwareModuleRequestBodyPost} which can directly be used in the
* RESTful-API.
*
* @return a single entry list of {@link SoftwareModuleRequestBodyPost}
*/
public List<SoftwareModuleRequestBodyPost> build() {
return Lists.newArrayList(doBuild(name));
}
/**
* Builds a list of multiple {@link SoftwareModuleRequestBodyPost} to create
* multiple software module at once. An increasing number will be added to
* the name of the software module. The version and type will remain the
* same.
*
* @param count
* the amount of software module body which should be created
* @return a list of {@link DistributionSetTypeRequestBodyPost}
*/
public List<SoftwareModuleRequestBodyPost> buildAsList(final int count) {
final ArrayList<SoftwareModuleRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index));
}
return bodyList;
}
private SoftwareModuleRequestBodyPost doBuild(final String prefixName) {
final SoftwareModuleRequestBodyPost body = new SoftwareModuleRequestBodyPost();
body.setName(prefixName);
body.setVersion(version);
body.setType(type);
return body;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,107 @@
/**
* 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.scenarios;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.RolloutResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.TargetResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.RolloutBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.TargetBuilder;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest;
import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutResponseBody;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModulesRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Example for creating and starting a Rollout.
*
*/
@Component
public class CreateStartedRolloutExample {
/* known software module type name and key */
private static final String SM_MODULE_TYPE = "firmware";
/* known distribution set type name and key */
private static final String DS_MODULE_TYPE = "firmware";
@Autowired
private DistributionSetResourceClient distributionSetResource;
@Autowired
private SoftwareModuleResourceClient softwareModuleResource;
@Autowired
private TargetResourceClient targetResource;
@Autowired
private RolloutResourceClient rolloutResource;
@Autowired
private DistributionSetTypeResourceClient distributionSetTypeResource;
@Autowired
private SoftwareModuleTypeResourceClient softwareModuleTypeResource;
/**
* Run the Rollout scenario.
*/
public void run() {
// create three SoftwareModuleTypes
final SoftwareModuleTypesRest createdSoftwareModuleTypes = softwareModuleTypeResource.createSoftwareModuleTypes(
new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE).maxAssignments(1).build())
.getBody();
// create one DistributionSetType
distributionSetTypeResource.createDistributionSetTypes(new DistributionSetTypeBuilder().key(DS_MODULE_TYPE)
.name(DS_MODULE_TYPE).mandatorymodules(createdSoftwareModuleTypes.get(0).getModuleId()).build())
.getBody();
// create one DistributionSet
final DistributionSetsRest distributionSetsRest = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name("rollout-example").version("1.0.0").type(DS_MODULE_TYPE).build())
.getBody();
// create three SoftwareModules
final SoftwareModulesRest softwareModulesRest = softwareModuleResource
.createSoftwareModules(
new SoftwareModuleBuilder().name("firmware").version("1.0.0").type(SM_MODULE_TYPE).build())
.getBody();
// Assign SoftwareModule to DistributionSet
distributionSetResource.assignSoftwareModules(distributionSetsRest.get(0).getDsId(),
new SoftwareModuleAssigmentBuilder().id(softwareModulesRest.get(0).getModuleId()).build());
// create ten targets
targetResource.createTargets(new TargetBuilder().controllerId("00-FF-AA-0").name("00-FF-AA-0")
.description("Targets used for rollout example").buildAsList(10));
// create a Rollout
final RolloutResponseBody rolloutResponseBody = rolloutResource
.create(new RolloutBuilder().name("MyRollout").groupSize(2).targetFilterQuery("name==00-FF-AA-0*")
.distributionSetId(distributionSetsRest.get(0).getDsId()).successThreshold("80")
.errorThreshold("50").build())
.getBody();
// start the created Rollout
rolloutResource.start(rolloutResponseBody.getRolloutId(), false);
}
}

View File

@@ -0,0 +1,134 @@
/**
* 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.scenarios;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModulesRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypesRest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
*
* Default getting started scenario.
*
*/
@Component
public class GettingStartedDefaultScenario {
private static final Logger LOGGER = LoggerFactory.getLogger(GettingStartedDefaultScenario.class);
/* known software module type name and key */
private static final String SM_MODULE_TYPE = "gettingstarted";
/* known distribution set type name and key */
private static final String DS_MODULE_TYPE = "gettingstarted";
/* known distribution name of this getting started example */
private static final String SM_EXAMPLE_NAME = "gettingstarted-example";
/* known distribution name of this getting started example */
private static final String DS_EXAMPLE_NAME = "gettingstarted-example";
@Autowired
private DistributionSetResourceClient distributionSetResource;
@Autowired
private DistributionSetTypeResourceClient distributionSetTypeResource;
@Autowired
private SoftwareModuleResourceClient softwareModuleResource;
@Autowired
private SoftwareModuleTypeResourceClient softwareModuleTypeResource;
/**
* Run the default getting started scenario.
*/
public void run() {
LOGGER.info("Running Getting-Started-Scenario...");
// create one SoftwareModuleTypes
LOGGER.info("Creating software module type {}", SM_MODULE_TYPE);
final SoftwareModuleTypesRest createdSoftwareModuleTypes = softwareModuleTypeResource.createSoftwareModuleTypes(
new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE).maxAssignments(1).build())
.getBody();
// create one DistributionSetType
LOGGER.info("Creating distribution set type {}", DS_MODULE_TYPE);
distributionSetTypeResource.createDistributionSetTypes(new DistributionSetTypeBuilder().key(DS_MODULE_TYPE)
.name(DS_MODULE_TYPE).mandatorymodules(createdSoftwareModuleTypes.get(0).getModuleId()).build());
// create three DistributionSet
final String dsVersion1 = "1.0.0";
final String dsVersion2 = "2.0.0";
final String dsVersion3 = "2.1.0";
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion1);
final DistributionSetsRest distributionSetsRest1 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion1).type(DS_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion2);
final DistributionSetsRest distributionSetsRest2 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion2).type(DS_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion3);
final DistributionSetsRest distributionSetsRest3 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion3).type(DS_MODULE_TYPE).build())
.getBody();
// create three SoftwareModules
final String swVersion1 = "1";
final String swVersion2 = "2";
final String swVersion3 = "3";
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion1);
final SoftwareModulesRest softwareModulesRest1 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion1).type(SM_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion2);
final SoftwareModulesRest softwareModulesRest2 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion2).type(SM_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion3);
final SoftwareModulesRest softwareModulesRest3 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion3).type(SM_MODULE_TYPE).build())
.getBody();
// Assign SoftwareModules to DistributionSet
LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion1,
DS_EXAMPLE_NAME, dsVersion1);
distributionSetResource.assignSoftwareModules(distributionSetsRest1.get(0).getDsId(),
new SoftwareModuleAssigmentBuilder().id(softwareModulesRest1.get(0).getModuleId()).build());
LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion2,
DS_EXAMPLE_NAME, dsVersion2);
distributionSetResource.assignSoftwareModules(distributionSetsRest2.get(0).getDsId(),
new SoftwareModuleAssigmentBuilder().id(softwareModulesRest2.get(0).getModuleId()).build());
LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion3,
DS_EXAMPLE_NAME, dsVersion3);
distributionSetResource.assignSoftwareModules(distributionSetsRest3.get(0).getDsId(),
new SoftwareModuleAssigmentBuilder().id(softwareModulesRest3.get(0).getModuleId()).build());
}
}

View File

@@ -0,0 +1,14 @@
#
# 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
#
hawkbit.url=localhost:8080
hawkbit.username=admin
hawkbit.password=admin
spring.main.show-banner=false

View File

@@ -0,0 +1,27 @@
<?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>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- Log message format -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.eclipse.hawkbit" level="info" />
<root level="error">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -1,186 +0,0 @@
/**
* 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.api.client;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.app.Start;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetsRest;
import org.eclipse.hawkbit.rest.resource.model.tag.AssignedDistributionSetRequestBody;
import org.eclipse.hawkbit.rest.resource.model.tag.DistributionSetTagAssigmentResultRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TagsRest;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
import feign.Feign;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
@Features("Example Tests - Management RESTful API Client")
@Stories("DistrubutionSet Tag Resource")
public class DistributionSetTagTest {
private DistrubutionSetTagResource distrubutionSetTagResource;
private static List<AssignedDistributionSetRequestBody> assignedTargetRequestBodies;
@BeforeClass
public static void startupServer() {
SpringApplication.run(Start.class, new String[0]);
createTargetsAssignment();
assignedTargetRequestBodies.add(new AssignedDistributionSetRequestBody().setDistributionSetId(100L));
}
@Before
public void setup() {
this.distrubutionSetTagResource = createDistrubutionSetTagResource();
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple request of distrubutionset tag by ID")
@Ignore
public void getDistributionSetTag() {
final TagsRest result = createDistributionSetTags(2);
assertThat(distrubutionSetTagResource.getDistributionSetTag(result.get(0).getTagId()).getName()).isEqualTo(
"Tag0");
deleteDistributionSets(result);
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple update of a distrubutionset tag")
@Ignore
public void updateDistributionSetTag() {
final TagsRest created = createDistributionSetTags(10);
distrubutionSetTagResource.updateDistributionSetTag(created.get(0).getTagId(), new TagRequestBodyPut()
.setDescription("Test").setName("Test").setColour("Green"));
final TagRest targetTag = distrubutionSetTagResource.getDistributionSetTag(created.get(0).getTagId());
assertThat(targetTag.getName()).isEqualTo("Test");
assertThat(targetTag.getDescription()).isEqualTo("Test");
assertThat(targetTag.getColour()).isEqualTo("Green");
deleteDistributionSets(created);
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple request of all assigned distrubutionsets by a distrubutionset tag.")
@Ignore
public void getDistributionSetByTagId() {
final TagsRest created = createDistributionSetTags(10);
distrubutionSetTagResource.assignDistributionSets(created.get(2).getTagId(), assignedTargetRequestBodies);
final DistributionSetsRest distributionSetsRest = distrubutionSetTagResource
.getAssignedDistributionSets(created.get(2).getTagId());
assertThat(distributionSetsRest).hasSize(5);
distrubutionSetTagResource.unassignDistributionSets(created.get(2).getTagId());
deleteDistributionSets(created);
}
@Test
@Description("Toggle request to unassigned all assigned distrubutionset and assign all unassigned distrubutionset.")
@Ignore
public void toggleTagAssignment() {
final TagsRest created = createDistributionSetTags(10);
final Long id = created.get(2).getTagId();
distrubutionSetTagResource.assignDistributionSets(id, assignedTargetRequestBodies);
distrubutionSetTagResource.unassignDistributionSet(id, assignedTargetRequestBodies.get(0)
.getDistributionSetId());
DistributionSetTagAssigmentResultRest assigmentResultRest = distrubutionSetTagResource.toggleTagAssignment(id,
assignedTargetRequestBodies);
final TagRest targetTag = distrubutionSetTagResource.getDistributionSetTag(created.get(2).getTagId());
assertThat(assigmentResultRest.getAssignedDistributionSets()).hasSize(1);
assertThat(assigmentResultRest.getUnassignedDistributionSets()).hasSize(0);
assigmentResultRest = distrubutionSetTagResource.toggleTagAssignment(id, assignedTargetRequestBodies);
assertThat(assigmentResultRest.getAssignedDistributionSets()).hasSize(0);
assertThat(assigmentResultRest.getUnassignedDistributionSets()).hasSize(5);
distrubutionSetTagResource.unassignDistributionSets(targetTag.getTagId());
deleteDistributionSets(created);
}
private void deleteDistributionSets(final List<TagRest> tags) {
for (final TagRest tag : tags) {
distrubutionSetTagResource.deleteDistributionSetTag(tag.getTagId());
}
}
private TagsRest createDistributionSetTags(final int number) {
final List<TagRequestBodyPut> tags = new ArrayList<>();
for (int i = 0; i < number; i++) {
tags.add(new TagRequestBodyPut().setDescription("Tag " + i).setName("Tag" + i).setColour("Red"));
}
final TagsRest result = distrubutionSetTagResource.createDistributionSetTags(tags);
assertThat(result).hasSize(number);
return result;
}
private DistrubutionSetTagResource createDistrubutionSetTagResource() {
final DistrubutionSetTagResource distrubutionSetTagResource = Feign.builder().logger(new Logger.ErrorLogger())
.logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder())
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(DistrubutionSetTagResource.class, "http://localhost:8080");
return distrubutionSetTagResource;
}
private static void createTargetsAssignment() {
final List<DistributionSetRequestBodyPost> sets = new ArrayList<>();
assignedTargetRequestBodies = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final DistributionSetRequestBodyPost bodyPost = (DistributionSetRequestBodyPost) new DistributionSetRequestBodyPost()
.setName("Ds" + i).setDescription("Ds" + i).setVersion("" + i);
sets.add(bodyPost);
}
final DistributionSetsRest result = createDistributionSetResource().createDistributionSets(sets);
for (final DistributionSetRest rest : result) {
assignedTargetRequestBodies.add(new AssignedDistributionSetRequestBody().setDistributionSetId(rest
.getDsId()));
}
}
private static DistributionSetResource createDistributionSetResource() {
final DistributionSetResource distributionSetResource = Feign.builder().logger(new Logger.ErrorLogger())
.logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder())
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(DistributionSetResource.class, "http://localhost:8080");
return distributionSetResource;
}
}

View File

@@ -1,182 +0,0 @@
/**
* 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.api.client;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.app.Start;
import org.eclipse.hawkbit.rest.resource.model.tag.AssignedTargetRequestBody;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRequestBodyPut;
import org.eclipse.hawkbit.rest.resource.model.tag.TagRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TagsRest;
import org.eclipse.hawkbit.rest.resource.model.tag.TargetTagAssigmentResultRest;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRest;
import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
import feign.Feign;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
@Features("Example Tests - Management RESTful API Client")
@Stories("Target Tag Resource")
public class TargetTagTest {
private TargetTagResource targetTagResource;
private static List<AssignedTargetRequestBody> assignedTargetRequestBodies;
@BeforeClass
public static void startupServer() {
SpringApplication.run(Start.class, new String[0]);
createTargetsAssignment();
assignedTargetRequestBodies.add(new AssignedTargetRequestBody().setControllerId("NotExist"));
}
@Before
public void setup() {
this.targetTagResource = createTargetTagResource();
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple request of target tag by ID")
@Ignore
public void getTargetTag() {
final TagsRest result = createTargetTags(2);
assertThat(targetTagResource.getTargetTag(result.get(0).getTagId()).getName()).isEqualTo("Tag0");
deleteTargets(result);
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple update of a target tag")
@Ignore
public void updateTargetTag() {
final TagsRest created = createTargetTags(10);
targetTagResource.updateTagretTag(created.get(0).getTagId(), new TagRequestBodyPut().setDescription("Test")
.setName("Test").setColour("Green"));
final TagRest targetTag = targetTagResource.getTargetTag(created.get(0).getTagId());
assertThat(targetTag.getName()).isEqualTo("Test");
assertThat(targetTag.getDescription()).isEqualTo("Test");
assertThat(targetTag.getColour()).isEqualTo("Green");
deleteTargets(created);
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple request of all assigned targets by a target tag.")
@Ignore
public void getTargetsByTargetTagId() {
final TagsRest created = createTargetTags(10);
final Long tagId = created.get(2).getTagId();
targetTagResource.assignTargets(tagId, assignedTargetRequestBodies);
final TagRest targetTag = targetTagResource.getTargetTag(tagId);
assertThat(targetTagResource.getAssignedTargets(tagId)).hasSize(5);
targetTagResource.unassignTargets(targetTag.getTagId());
deleteTargets(created);
}
@Test
@Description("Toggle request to unassigned all assigned targets and assign all unassigned targets.")
@Ignore
public void toggleTagAssignment() {
final TagsRest created = createTargetTags(10);
final Long id = created.get(2).getTagId();
targetTagResource.assignTargets(id, assignedTargetRequestBodies);
targetTagResource.unassignTarget(id, assignedTargetRequestBodies.get(0).getControllerId());
TargetTagAssigmentResultRest assigmentResultRest = targetTagResource.toggleTagAssignment(id,
assignedTargetRequestBodies);
final TagRest targetTag = targetTagResource.getTargetTag(created.get(2).getTagId());
assertThat(assigmentResultRest.getAssignedTargets()).hasSize(1);
assertThat(assigmentResultRest.getUnassignedTargets()).hasSize(0);
assigmentResultRest = targetTagResource.toggleTagAssignment(id, assignedTargetRequestBodies);
assertThat(assigmentResultRest.getAssignedTargets()).hasSize(0);
assertThat(assigmentResultRest.getUnassignedTargets()).hasSize(5);
targetTagResource.unassignTargets(targetTag.getTagId());
deleteTargets(created);
}
private void deleteTargets(final List<TagRest> tags) {
for (final TagRest tag : tags) {
targetTagResource.deleteTargetTag(tag.getTagId());
}
}
private TagsRest createTargetTags(final int number) {
final List<TagRequestBodyPut> tags = new ArrayList<>();
for (int i = 0; i < number; i++) {
tags.add(new TagRequestBodyPut().setDescription("Tag " + i).setName("Tag" + i).setColour("Red"));
}
final TagsRest result = targetTagResource.createTargetTag(tags);
assertThat(result).hasSize(number);
return result;
}
private TargetTagResource createTargetTagResource() {
final TargetTagResource targetResource = Feign.builder().logger(new Logger.ErrorLogger())
.logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder())
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(TargetTagResource.class, "http://localhost:8080");
return targetResource;
}
private static void createTargetsAssignment() {
final List<TargetRequestBody> targets = new ArrayList<>();
assignedTargetRequestBodies = new ArrayList<>();
for (int i = 0; i < 5; i++) {
targets.add(new TargetRequestBody().setControllerId("test" + i).setName("testDevice"));
}
final TargetsRest result = createTargetResource().createTargets(targets);
for (final TargetRest rest : result) {
assignedTargetRequestBodies.add(new AssignedTargetRequestBody().setControllerId(rest.getControllerId()));
}
}
private static TargetResource createTargetResource() {
final TargetResource targetResource = Feign.builder().logger(new Logger.ErrorLogger())
.logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder())
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(TargetResource.class, "http://localhost:8080");
return targetResource;
}
}

View File

@@ -1,119 +0,0 @@
/**
* 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.api.client;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.app.Start;
import org.eclipse.hawkbit.rest.resource.model.target.TargetPagedList;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRest;
import org.eclipse.hawkbit.rest.resource.model.target.TargetsRest;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Description;
import feign.Feign;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Example Tests - Management RESTful API Client")
@Stories("Target Resource")
public class TargetTest {
@BeforeClass
public static void startupServer() {
SpringApplication.run(Start.class, new String[0]);
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple request of target by ID")
@Ignore
public void getTarget() {
final TargetResource targetResource = createTargetResource();
final TargetsRest result = createTargets(targetResource, 1);
assertThat(targetResource.getTarget("test0").getName()).isEqualTo("testDevice");
deleteTargets(targetResource, result);
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple request of all targets with defined page sizing information (i.e. offset and limit).")
@Ignore
public void getTargetsAsPagedListWithDefinedPageSizing() {
final TargetResource targetResource = createTargetResource();
final TargetsRest created = createTargets(targetResource, 20);
final TargetPagedList queryResult = targetResource.getTargets(0, 10);
assertThat(queryResult.getContent()).hasSize(10);
assertThat(queryResult.getTotal()).isEqualTo(20);
assertThat(queryResult.getSize()).isEqualTo(10);
deleteTargets(targetResource, created);
}
// disabled as this runs not on CI environments.
@Test
@Description("Simple request of all targets with defualt paging parameters.")
@Ignore
public void getTargetsAsPagedListWithDefaultPageSizing() {
final TargetResource targetResource = createTargetResource();
final TargetsRest created = createTargets(targetResource, 20);
final TargetPagedList queryResult = targetResource.getTargets();
assertThat(queryResult.getContent()).hasSize(20);
assertThat(queryResult.getTotal()).isEqualTo(20);
assertThat(queryResult.getSize()).isEqualTo(20);
deleteTargets(targetResource, created);
}
private void deleteTargets(final TargetResource targetResource, final List<TargetRest> targets) {
for (final TargetRest targetRest : targets) {
targetResource.deleteTarget(targetRest.getControllerId());
}
}
private TargetsRest createTargets(final TargetResource targetResource, final int number) {
final List<TargetRequestBody> targets = new ArrayList<>();
for (int i = 0; i < number; i++) {
targets.add(new TargetRequestBody().setControllerId("test" + i).setName("testDevice"));
}
final TargetsRest result = targetResource.createTargets(targets);
assertThat(result).hasSize(number);
return result;
}
private TargetResource createTargetResource() {
final TargetResource targetResource = Feign.builder().logger(new Logger.ErrorLogger())
.logLevel(Logger.Level.BASIC).decoder(new JacksonDecoder()).encoder(new JacksonEncoder())
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(TargetResource.class, "http://localhost:8080");
return targetResource;
}
}

View File

@@ -88,7 +88,7 @@ public class MongoDBTestRule implements TestRule {
System.setProperty("spring.data.mongodb.port", String.valueOf(port));
}
Version version = Version.V3_1_0;
Version version = Version.V3_0_8;
if (System.getProperty("inf.mongodb.version") != null) {
version = Version.valueOf("V" + System.getProperty("inf.mongodb.version").trim().replaceAll("\\.", "_"));
}

View File

@@ -34,6 +34,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.google.common.io.BaseEncoding;
import com.mongodb.gridfs.GridFSDBFile;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Repository")
@Stories("Artifact Store MongoDB")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { ArtifactStoreAutoConfiguration.class, TestConfiguration.class })
public class ArtifactStoreTest {
@@ -48,6 +54,7 @@ public class ArtifactStoreTest {
private GridFsOperations gridFs;
@Test
@Description("Ensures that storage in MongoDB is correctly executed.s")
public void storeArtifactInMongoDB() {
final int filelengthBytes = 128;
final String filename = "testfile.json";
@@ -60,6 +67,7 @@ public class ArtifactStoreTest {
}
@Test
@Description("Ensures that search by SHA1 hash (which is used by hawkBit as artifact ID) finds the expected results.")
public void findArtifactBySHA1Hash() throws NoSuchAlgorithmException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
@@ -72,6 +80,7 @@ public class ArtifactStoreTest {
}
@Test
@Description("Ensures that search by MD5 hash finds the expected results.")
public void findArtifactByMD5Hash() throws NoSuchAlgorithmException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
@@ -84,6 +93,7 @@ public class ArtifactStoreTest {
}
@Test
@Description("Ensures that artifact content can be read through InputStream.")
public void getInputStreamFromArtifact() throws IOException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
@@ -103,7 +113,8 @@ public class ArtifactStoreTest {
}
@Test
public void deleteArtifactWithOnlyOneTenantLast() throws NoSuchAlgorithmException {
@Description("Ensures that artifact delete actually results in deletion from database.")
public void deleteArtifact() throws NoSuchAlgorithmException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
final String contentType = "application/json";

View File

@@ -72,5 +72,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -1,27 +0,0 @@
/**
* 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.autoconfigure.conf;
import org.eclipse.hawkbit.ControllerPollProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* Enable the Controlle Poll.
*
*
*
*/
@Configuration
@ConditionalOnClass(ControllerPollProperties.class)
@EnableConfigurationProperties(ControllerPollProperties.class)
public class ControllerPollAutoConfiguration {
}

View File

@@ -12,6 +12,7 @@ import java.util.concurrent.Executor;
import org.eclipse.hawkbit.eventbus.EventBusSubscriberProcessor;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.repository.model.helper.EventBusHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -54,4 +55,12 @@ public class EventBusAutoConfiguration {
return new EventBusSubscriberProcessor();
}
/**
* @return the singleton instance of the {@link EventBusHolder}
*/
@Bean
public EventBusHolder eventBusHolder() {
return EventBusHolder.getInstance();
}
}

View File

@@ -13,17 +13,29 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties for the async configurer.
*
*
*/
@ConfigurationProperties("hawkbit.threadpool")
public class AsyncConfigurerThreadpoolProperties {
/**
* Max queue size for central event executor.
*/
private Integer queuesize = 250;
/**
* Core processing threads for central event executor.
*/
private Integer corethreads = 5;
/**
* Maximum thread pool size for central event executor.
*/
private Integer maxthreads = 50;
/**
* When the number of threads is greater than the core, this is the maximum
* time that excess idle threads will wait for new tasks before terminating.
*/
private Long idletimeout = 10000L;
public Integer getQueuesize() {

View File

@@ -26,10 +26,9 @@ import org.springframework.security.concurrent.DelegatingSecurityContextExecutor
import com.google.common.util.concurrent.ThreadFactoryBuilder;
/**
*
* Central event processors inside update server.
*
*/
@Configuration
@EnableConfigurationProperties(AsyncConfigurerThreadpoolProperties.class)
public class ExecutorAutoConfiguration {
@@ -40,7 +39,7 @@ public class ExecutorAutoConfiguration {
private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties;
/**
* @return ExecutorService for general pupose multi threaded operations
* @return ExecutorService for general purpose multi threaded operations
*/
@Bean
@ConditionalOnMissingBean

View File

@@ -20,7 +20,7 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
import org.eclipse.hawkbit.security.SecurityProperties;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.SpringSecurityAuditorAware;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger;
@@ -53,7 +53,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
*
*/
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
@EnableConfigurationProperties(DdiSecurityProperties.class)
public class SecurityAutoConfiguration {
/**

View File

@@ -29,31 +29,31 @@ import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationTok
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.rest.resource.RestConstants;
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.DosFilter;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
import org.eclipse.hawkbit.security.HttpDownloadAuthenticationFilter;
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
import org.eclipse.hawkbit.security.SecurityProperties;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
import org.springframework.cache.Cache;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -94,17 +94,11 @@ import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSucc
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
@EnableWebMvcSecurity
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class SecurityManagedConfiguration implements EnvironmentAware {
public class SecurityManagedConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(SecurityManagedConfiguration.class);
private static final String SP_SERVER_CONFIG_PREFIX = "hawkbit.server.";
private RelaxedPropertyResolver environment;
@Override
public void setEnvironment(final Environment environment) {
this.environment = new RelaxedPropertyResolver(environment, SP_SERVER_CONFIG_PREFIX);
}
@Autowired
private HawkbitSecurityProperties securityProperties;
/**
* {@link WebSecurityConfigurer} for the internal SP controller API.
@@ -119,33 +113,36 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
@Autowired
private ControllerManagement controllerManagement;
@Autowired
private SystemManagement systemManagement;
private TenantConfigurationManagement tenantConfigurationManagement;
@Autowired
private TenantAware tenantAware;
@Autowired
private SecurityProperties securityConfiguration;
private DdiSecurityProperties ddiSecurityConfiguration;
@Autowired
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Override
protected void configure(final HttpSecurity http) throws Exception {
final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
securityConfiguration.getRpCnHeader(), securityConfiguration.getRpSslIssuerHashHeader(),
systemManagement, tenantAware);
ddiSecurityConfiguration.getRp().getCnHeader(),
ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
tenantAware, systemSecurityContext);
securityHeaderFilter.setAuthenticationManager(authenticationManager());
securityHeaderFilter.setCheckForPrincipalChanges(true);
securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
systemManagement, tenantAware, controllerManagement);
tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
securityTokenFilter.setAuthenticationManager(authenticationManager());
securityTokenFilter.setCheckForPrincipalChanges(true);
securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
systemManagement, tenantAware);
tenantConfigurationManagement, tenantAware, systemSecurityContext);
gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager());
gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
@@ -158,7 +155,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
}
if (securityConfiguration.getAnonymousEnabled()) {
if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) {
LOG.info(
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
@@ -177,19 +174,10 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
}
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.config.annotation.web.configuration.
* WebSecurityConfigurerAdapter
* #configure(org.springframework.security.config.annotation.
* authentication.builders. AuthenticationManagerBuilder)
*/
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(
new PreAuthTokenSourceTrustAuthenticationProvider(securityConfiguration.getRpTrustedIPs()));
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
ddiSecurityConfiguration.getRp().getTrustedIPs()));
}
}
@@ -204,13 +192,10 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
public FilterRegistrationBean dosFilter() {
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean
.setFilter(
new DosFilter(environment.getProperty("security.dos.filter.maxRead", Integer.class, 200),
environment.getProperty("security.dos.filter.maxWrite", Integer.class, 50),
environment.getProperty("security.dos.filter.whitelist"), environment
.getProperty("security.clients.blacklist"),
environment.getProperty("security.rp.remote_ip_header", String.class, "X-Forwarded-For")));
filterRegBean.setFilter(new DosFilter(securityProperties.getDos().getFilter().getMaxRead(),
securityProperties.getDos().getFilter().getMaxWrite(),
securityProperties.getDos().getFilter().getWhitelist(), securityProperties.getClients().getBlacklist(),
securityProperties.getClients().getRemoteIpHeader()));
filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*");
return filterRegBean;
}
@@ -310,8 +295,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
@Configuration
@Order(400)
@EnableVaadinSecurity
public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter
implements EnvironmentAware {
public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private static final String XFRAME_OPTION_DENY = "DENY";
private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN";
@@ -320,13 +304,8 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
private VaadinSecurityContext vaadinSecurityContext;
@Autowired
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
private RelaxedPropertyResolver environment;
@Override
public void setEnvironment(final Environment environment) {
this.environment = new RelaxedPropertyResolver(environment, SP_SERVER_CONFIG_PREFIX);
}
@Autowired
private HawkbitSecurityProperties securityProperties;
/**
* post construct for setting the authentication success handler for the
@@ -379,13 +358,13 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
protected void configure(final HttpSecurity http) throws Exception {
// configuration xframe-option
final String confXframeOption = environment.getProperty("security.xframe.option", XFRAME_OPTION_DENY);
final String confAllowFromUri = environment.getProperty("security.xframe.option.allowfrom");
if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri == null) {
final String confXframeOption = securityProperties.getXframe().getOption();
final String confAllowFromUri = securityProperties.getXframe().getAllowfrom();
if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri.isEmpty()) {
// if allow-from option is specified but no allowFromUri throw
// exception
throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM"
+ " but no hawkbit.server.security.xframe.option.allowfrom has been set, "
+ " but no hawkbit.server.security.xframe.allowfrom has been set, "
+ "please ensure to set allow from URIs");
}
@@ -461,7 +440,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
public static class IdRestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private SecurityProperties securityConfiguration;
private DdiSecurityProperties ddiSecurityConfiguration;
@Autowired
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
@@ -483,8 +462,8 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(
new PreAuthTokenSourceTrustAuthenticationProvider(securityConfiguration.getRpTrustedIPs()));
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
ddiSecurityConfiguration.getRp().getTrustedIPs()));
}
}

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.autoconfigure.url;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.hawkbit.HawkbitServerProperties;
import org.eclipse.hawkbit.api.HostnameResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -27,11 +28,11 @@ import com.google.common.base.Throwables;
*
*/
@Configuration
@EnableConfigurationProperties(ServerProperties.class)
@EnableConfigurationProperties(HawkbitServerProperties.class)
public class PropertyHostnameResolverAutoConfiguration {
@Autowired
private ServerProperties serverProperties;
private HawkbitServerProperties serverProperties;
/**
* @return the default autoconfigure hostname resolver implementation which

View File

@@ -1,30 +0,0 @@
/**
* 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.autoconfigure.url;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties for the server e.g. the server's URL which must be configured.
*
*
*/
@ConfigurationProperties("hawkbit.server")
public class ServerProperties {
private String url = "http://localhost:8080";
public String getUrl() {
return url;
}
public void setUrl(final String url) {
this.url = url;
}
}

View File

@@ -11,5 +11,4 @@ org.eclipse.hawkbit.autoconfigure.eventbus.EventBusAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.scheduling.AsyncConfigurerAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.cache.RedisAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.conf.ControllerPollAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration

View File

@@ -7,12 +7,6 @@
# http://www.eclipse.org/legal/epl-v10.html
#
# Tomcat / Server
server.tomcat.compression=on
spring.http.gzip.mime-types=text/html,text/xml,text/plain,application/json,application/javascript,text/css,application/x-javascript,text/javascript,application/vnd.ms-fontobject,application/x-font-opentype,application/x-font-truetype,application/x-font-ttf,application/xml,font/eot,font/opentype,font/otf,image/svg+xml,image/vnd.microsoft.icon
server.tomcat.compressable-mime-types=${spring.http.gzip.mime-types}
spring.http.gzip.min-gzip-size=256
# JPA / Datasource
spring.jpa.eclipselink.eclipselink.weaving=false
spring.jpa.database=H2
@@ -21,7 +15,6 @@ spring.datasource.driverClassName=org.h2.Driver
# MongoDB for artifact-repository
spring.data.mongodb.uri=mongodb://localhost/artifactrepo
spring.data.mongo.repositories.enabled=true
# Flyway DDL
flyway.enabled=true
@@ -29,29 +22,26 @@ flyway.initOnMigrate=true
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
# Vaadin Servlet
vaadin.static.servlet.params.resourceCacheTime=${spring.resources.cache-period}
vaadin.static.servlet.params.productionMode=true
vaadin.servlet.params.productionMode=true
vaadin.servlet.params.resourceCacheTime=${spring.resources.cache-period}
vaadin.servlet.productionMode=true
vaadin.servlet.urlMapping=/UI/*
vaadin.servlet.params.heartbeatInterval=60
vaadin.servlet.params.closeIdleSessions=false
# Spring MVC
spring.mvc.favicon.enabled=false
vaadin.servlet.heartbeatInterval=60
vaadin.servlet.closeIdleSessions=false
# Defines the thread pool executor
hawkbit.threadpool.corethreads=5
hawkbit.threadpool.maxthreads=20
hawkbit.threadpool.idletimeout=10000
hawkbit.threadpool.queuesize=250
hawkbit.threadpool.queuesize=20000
# Defines the polling time for the controllers in HH:MM:SS notation
hawkbit.controller.pollingTime=00:05:00
hawkbit.controller.pollingOverdueTime=00:05:00
hawkbit.controller.maxPollingTime=23:59:59
hawkbit.controller.minPollingTime=00:00:30
# Attention: if you want to use a maximumPollingTime greater 23:59:59 you have to update the DurationField in the configuration window
## Configuration for RabbitMQ integration
# Configuration for RabbitMQ integration
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver

View File

@@ -37,6 +37,11 @@
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->

View File

@@ -26,8 +26,6 @@ import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
* The spring Redis configuration which is enabled by using the profile
* {@code redis} to use a Redis server as cache.
*
*
*
*/
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
@@ -75,7 +73,7 @@ public class RedisConfiguration {
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(new JdkSerializationRedisSerializer());
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());

View File

@@ -14,14 +14,18 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* Bean which holds the necessary properties for configuring the Redis
* connection.
*
*
*
*
*/
@ConfigurationProperties("hawkbit.server.redis")
public class RedisProperties {
/**
* Redis server hostname.
*/
private String host;
/**
* Redis server port.
*/
private int port;
/**

View File

@@ -95,7 +95,7 @@ public class EventDistributor {
* wants to subscribe
*/
public Collection<Topic> getTopics() {
final List<Topic> topics = new ArrayList<Topic>();
final List<Topic> topics = new ArrayList<>();
topics.add(new PatternTopic(SUB_DISTRIBUTION_CHANNEL));
return topics;
}

View File

@@ -29,7 +29,13 @@ import org.springframework.hateoas.Identifiable;
import com.google.common.eventbus.EventBus;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cluster Cache")
@Stories("EventDistributor Test")
@RunWith(MockitoJUnitRunner.class)
// TODO: create description annotations
public class EventDistributorTest {
@Mock

View File

@@ -13,6 +13,11 @@ import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.cache.RedisProperties;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cluster Cache")
@Stories("Redis Properties Test")
public class RedisPropertiesTest {
@Test

1
hawkbit-core/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/.apt_generated/

View File

@@ -32,7 +32,6 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -44,6 +43,11 @@
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -8,35 +8,51 @@
*/
package org.eclipse.hawkbit;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.stereotype.Component;
/**
* Defines the polling time for the controllers in HH:MM:SS notation.
* Defines global configuration for the controllers/clients on the provisioning
* targets/devices.
*
*
* Note: many of the controller related properties can be overridden on tenant
* level. As a result they are not defined here but in
* {@link TenantConfigurationKey} and injected using {@link EnvironmentAware}.
*
*
*
*/
@Component
@ConfigurationProperties(prefix = "hawkbit.controller")
public class ControllerPollProperties {
private String pollingTime = "00:05:00";
private String pollingOverdueTime = "00:05:00";
/**
* Maximum polling time that can be configured by a tenant in HH:MM:SS
* notation.
*/
private String maxPollingTime = "23:59:00";
public String getPollingTime() {
return pollingTime;
/**
* Minimum polling time that can be configured by a tenant in HH:MM:SS
* notation.
*/
private String minPollingTime = "00:00:30";
public String getMaxPollingTime() {
return maxPollingTime;
}
public void setPollingTime(final String pollingTime) {
this.pollingTime = pollingTime;
public void setMaxPollingTime(final String maxPollingTime) {
this.maxPollingTime = maxPollingTime;
}
public String getPollingOverdueTime() {
return pollingOverdueTime;
public String getMinPollingTime() {
return minPollingTime;
}
public void setPollingOverdueTime(final String pollingOverdue) {
this.pollingOverdueTime = pollingOverdue;
public void setMinPollingTime(final String minPollingTime) {
this.minPollingTime = minPollingTime;
}
}

View File

@@ -0,0 +1,97 @@
/**
* 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;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties for the server e.g. the server's URL which must be configured.
*
*/
@ConfigurationProperties("hawkbit.server")
public class HawkbitServerProperties {
/**
* Defines under which URI the update server can be reached. Used to
* calculate download URLs for DMF transmitted update actions.
*/
private String url = "http://localhost:8080";
private final Build build = new Build();
public Build getBuild() {
return build;
}
/**
* Build information of the hawkBit instance. Influenced by maven.
*
*/
public static class Build {
/**
* Project artifact ID.
*/
private String artifact = "";
/**
* Project name.
*/
private String name = "";
/**
* Project description.
*/
private String description = "";
/**
* Project version.
*/
private String version = "";
public String getArtifact() {
return artifact;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getVersion() {
return version;
}
public void setArtifact(final String artifact) {
this.artifact = artifact;
}
public void setName(final String name) {
this.name = name;
}
public void setDescription(final String description) {
this.description = description;
}
public void setVersion(final String version) {
this.version = version;
}
}
public String getUrl() {
return url;
}
public void setUrl(final String url) {
this.url = url;
}
}

View File

@@ -51,7 +51,12 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
@Override
public Cache getCache(final String name) {
final String currentTenant = tenantAware.getCurrentTenant().toUpperCase();
String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant == null) {
return null;
}
currentTenant = currentTenant.toUpperCase();
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
return null;
}
@@ -60,7 +65,12 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
@Override
public Collection<String> getCacheNames() {
final String currentTenant = tenantAware.getCurrentTenant().toUpperCase();
String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant == null) {
return null;
}
currentTenant = currentTenant.toUpperCase();
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
return Collections.emptyList();
}

View File

@@ -0,0 +1,45 @@
/**
* 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.eventbus.event;
/**
* Abstract event definition class which holds the necessary revsion and tenant
* information which every event needs.
*
* @author Michael Hirsch
* @see AbstractDistributedEvent for events which should be distributed to other
* cluster nodes
*/
public class AbstractEvent implements Event {
private final long revision;
private final String tenant;
/**
* @param revision
* the revision number of the event
* @param tenant
* the tenant of the event
*/
protected AbstractEvent(final long revision, final String tenant) {
this.revision = revision;
this.tenant = tenant;
}
@Override
public long getRevision() {
return revision;
}
@Override
public String getTenant() {
return tenant;
}
}

View File

@@ -17,7 +17,7 @@ import java.net.URI;
*
*
*/
public class CancelTargetAssignmentEvent {
public class CancelTargetAssignmentEvent extends AbstractEvent {
private final String controllerId;
private final Long actionId;
@@ -26,6 +26,10 @@ public class CancelTargetAssignmentEvent {
/**
* Creates a new {@link CancelTargetAssignmentEvent}.
*
* @param revision
* the revision for this event
* @param tenant
* the tenant for this event
* @param controllerId
* the ID of the controller
* @param actionId
@@ -33,7 +37,9 @@ public class CancelTargetAssignmentEvent {
* @param targetAdress
* the targetAdress of the target
*/
public CancelTargetAssignmentEvent(final String controllerId, final Long actionId, final URI targetAdress) {
public CancelTargetAssignmentEvent(final long revision, final String tenant, final String controllerId,
final Long actionId, final URI targetAdress) {
super(revision, tenant);
this.controllerId = controllerId;
this.actionId = actionId;
this.targetAdress = targetAdress;

View File

@@ -65,6 +65,7 @@ public enum SpServerError {
*/
SP_REST_SORT_PARAM_INVALID_DIRECTION("hawkbit.server.error.rest.param.invalidDirection",
"The given sort parameter direction does not exist"),
/**
*
*/
@@ -174,7 +175,23 @@ public enum SpServerError {
*
*/
SP_REPO_ENTITY_READ_ONLY("hawkbit.server.error.entityreadonly",
"The given entity is read only and the change cannot be completed.");
"The given entity is read only and the change cannot be completed."),
/**
*
*/
SP_CONFIGURATION_VALUE_INVALID("hawkbit.server.error.configValueInvalid",
"The given configuration value is invalid."),
/**
*
*/
SP_CONFIGURATION_KEY_INVALID("hawkbit.server.error.configKeyInvalid", "The given configuration key is invalid."),
/**
*
*/
SP_ROLLOUT_ILLEGAL_STATE("hawkbit.server.error.rollout.illegalstate",
"The rollout is currently in the wrong state for the current operation");
private final String key;
private final String message;

View File

@@ -74,6 +74,9 @@ public abstract class SpServerRtException extends RuntimeException {
this.error = error;
}
/**
* @return the SpServerError which is wrapped by this exception
*/
public SpServerError getError() {
return error;
}

View File

@@ -20,7 +20,12 @@ public enum ActionStatusFields implements FieldNameProvider {
/**
* The id field.
*/
ID("id");
ID("id"),
/**
* The reportedAt field.
*/
REPORTEDAT("createdAt");
private final String fieldName;

View File

@@ -20,7 +20,7 @@ import java.util.Map;
*/
public interface FieldNameProvider {
/**
* Seperator for the sub attributes
* Separator for the sub attributes
*/
public static final String SUB_ATTRIBUTE_SEPERATOR = ".";

View File

@@ -0,0 +1,40 @@
/**
* 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.repository;
/**
* Describing the fields of the Rollout model which can be used in the REST API
* e.g. for sorting etc.
*
*/
public enum RolloutFields implements FieldNameProvider {
/**
* The name field.
*/
NAME("name"),
/**
* The description field.
*/
DESCRIPTION("description"),
/**
* The id field.
*/
ID("id");
private final String fieldName;
private RolloutFields(final String fieldName) {
this.fieldName = fieldName;
}
@Override
public String getFieldName() {
return fieldName;
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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.repository;
/**
* Describing the fields of the RolloutGroup model which can be used in the REST
* API e.g. for sorting etc.
*
*/
public enum RolloutGroupFields implements FieldNameProvider {
/**
* The name field.
*/
NAME("name"),
/**
* The description field.
*/
DESCRIPTION("description"),
/**
* The id field.
*/
ID("id");
private final String fieldName;
private RolloutGroupFields(final String fieldName) {
this.fieldName = fieldName;
}
@Override
public String getFieldName() {
return fieldName;
}
}

View File

@@ -36,7 +36,7 @@ public enum SoftwareModuleTypeFields implements FieldNameProvider {
/**
* The max ds assignments field.
*/
MAX("maxAssignments");
MAXASSIGNMENTS("maxAssignments");
private final String fieldName;

View File

@@ -51,7 +51,16 @@ public enum TargetFields implements FieldNameProvider {
*/
ATTRIBUTE("targetInfo.controllerAttributes", true),
/**
* distribution sets which is assigned to the target.
*/
ASSIGNEDDS("assignedDistributionSet", "name", "version"),
/**
* distribution sets which is installed on the target.
*/
INSTALLEDDS("targetInfo.installedDistributionSet", "name", "version"),
/**
* The tags field.
*/

View File

@@ -0,0 +1,115 @@
/**
* 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.tenancy.configuration;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
/**
* This class is a helper for converting a duration into a string and for the
* other way. The string is in the format expected in configuration and database
* {@link #DURATION_FORMAT}.
*
*/
public final class DurationHelper {
/**
* Duration validation utility class. Checks if the requested duration is in
* the defined min/max range.
*
*/
public static class DurationRangeValidator {
final Duration min;
final Duration max;
private DurationRangeValidator(final Duration min, final Duration max) {
this.min = min;
this.max = max;
}
public boolean isWithinRange(final Duration duration) {
return duration.compareTo(min) > 0 && duration.compareTo(max) < 0;
}
}
/**
* Format of the String expected in configuration file and in the database.
*/
public static final String DURATION_FORMAT = "HH:mm:ss";
private DurationHelper() {
// utility class
}
/**
* Creates a {@link DurationRangeValidator}.
*
* @param min
* imum of range.
* @param max
* imum of range.
* @return {@link DurationRangeValidator} range.
*/
public static DurationRangeValidator durationRangeValidator(final Duration min, final Duration max) {
return new DurationRangeValidator(min, max);
}
/**
* Converts a Duration into a formatted String
*
* @param duration
* duration, which will be converted into a formatted String
* @return String in the duration format, specified at
* {@link #DURATION_FORMAT}
*/
public static String durationToFormattedString(final Duration duration) {
if (duration == null) {
return null;
}
return LocalTime.ofNanoOfDay(duration.toNanos()).format(DateTimeFormatter.ofPattern(DURATION_FORMAT));
}
/**
* Converts a formatted String into a Duration object.
*
* @param formattedDuration
* String in {@link #DURATION_FORMAT}
* @return duration
* @throws DateTimeParseException
* when String is in wrong format
*/
public static Duration formattedStringToDuration(final String formattedDuration) {
if (formattedDuration == null) {
return null;
}
final TemporalAccessor ta = DateTimeFormatter.ofPattern(DURATION_FORMAT).parse(formattedDuration.trim());
return Duration.between(LocalTime.MIDNIGHT, LocalTime.from(ta));
}
/**
* converts values of time constants to a Duration object..
*
* @param hours
* count of hours
* @param minutes
* count of minutes
* @param seconds
* count of seconds
* @return duration
*/
public static Duration getDurationByTimeValues(final long hours, final long minutes, final long seconds) {
return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds);
}
}

View File

@@ -0,0 +1,63 @@
/**
* 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.tenancy.configuration;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
/**
* The {@link #InvalidTenantConfigurationKeyException} is thrown when an invalid
* configuration key is used.
*
*/
public class InvalidTenantConfigurationKeyException extends SpServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIGURATION_KEY_INVALID;
/**
* Default constructor.
*/
public InvalidTenantConfigurationKeyException() {
super(THIS_ERROR);
}
/**
* Parameterized constructor.
*
* @param cause
* of the exception
*/
public InvalidTenantConfigurationKeyException(final Throwable cause) {
super(THIS_ERROR, cause);
}
/**
* Parameterized constructor.
*
* @param message
* of the exception
* @param cause
* of the exception
*/
public InvalidTenantConfigurationKeyException(final String message, final Throwable cause) {
super(message, THIS_ERROR, cause);
}
/**
* Parameterized constructor.
*
* @param message
* of the exception
*/
public InvalidTenantConfigurationKeyException(final String message) {
super(message, THIS_ERROR);
}
}

View File

@@ -8,12 +8,21 @@
*/
package org.eclipse.hawkbit.tenancy.configuration;
import java.util.Arrays;
import java.util.Optional;
import org.eclipse.hawkbit.ControllerPollProperties;
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator;
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator;
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationStringValidator;
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidator;
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException;
import org.springframework.context.ApplicationContext;
/**
* An enum which defines the tenant specific configurations which can be
* configured for each tenant seperately.
*
*
*
* configured for each tenant separately. The non overridable properties are
* configured in {@link ControllerPollProperties} instead.
*
*/
public enum TenantConfigurationKey {
@@ -21,51 +30,68 @@ public enum TenantConfigurationKey {
/**
* boolean value {@code true} {@code false}.
*/
AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled",
"hawkbit.server.controller.security.authentication.header.enabled", Boolean.FALSE.toString()),
AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled", "hawkbit.server.ddi.security.authentication.header.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class),
/**
*
*/
AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority",
"hawkbit.server.controller.security.authentication.header.authority", Boolean.FALSE.toString()),
AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority", "hawkbit.server.ddi.security.authentication.header.authority", String.class, Boolean.FALSE.toString(), TenantConfigurationStringValidator.class),
/**
* boolean value {@code true} {@code false}.
*/
AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled",
"hawkbit.server.controller.security.authentication.targettoken.enabled", Boolean.FALSE.toString()),
AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled", "hawkbit.server.ddi.security.authentication.targettoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class),
/**
* boolean value {@code true} {@code false}.
*/
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled",
"hawkbit.server.controller.security.authentication.gatewaytoken.enabled", Boolean.FALSE.toString()),
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled", "hawkbit.server.ddi.security.authentication.gatewaytoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class),
/**
* string value which holds the name of the security token key.
*/
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name",
"hawkbit.server.controller.security.authentication.gatewaytoken.name", null),
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name", "hawkbit.server.ddi.security.authentication.gatewaytoken.name", String.class, null, TenantConfigurationStringValidator.class),
/**
* string value which holds the actual security-key of the gateway security
* token.
*/
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key",
"hawkbit.server.controller.security.authentication.gatewaytoken.key", null);
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key", "hawkbit.server.ddi.security.authentication.gatewaytoken.key", String.class, null, TenantConfigurationStringValidator.class),
/**
* string value which holds the polling time interval in the format HH:mm:ss
*/
POLLING_TIME_INTERVAL("pollingOverdueTime", "hawkbit.controller.pollingOverdueTime", String.class, null, TenantConfigurationPollingDurationValidator.class),
/**
* string value which holds the polling time interval in the format HH:mm:ss
*/
POLLING_OVERDUE_TIME_INTERVAL("pollingTime", "hawkbit.controller.pollingTime", String.class, null, TenantConfigurationPollingDurationValidator.class);
private final String keyName;
private final String defaultKeyName;
private final Class<?> dataType;
private final String defaultValue;
private final Class<? extends TenantConfigurationValidator> validator;
/**
*
* @param key
* the property key name
* @param allowedValues
* @param defaultKeyName
* the allowed values for this specific key
* @param dataType
* the class of the property
* @param defaultValue
* value which should be returned, in case there is no value in
* the database
* @param validator
* Validator which validates, that property is of correct format
*/
private TenantConfigurationKey(final String key, final String defaultKeyName, final String defaultValue) {
private TenantConfigurationKey(final String key, final String defaultKeyName, final Class<?> dataType,
final String defaultValue, final Class<? extends TenantConfigurationValidator> validator) {
this.keyName = key;
this.dataType = dataType;
this.defaultKeyName = defaultKeyName;
this.defaultValue = defaultValue;
this.validator = validator;
}
/**
@@ -88,4 +114,49 @@ public enum TenantConfigurationKey {
public String getDefaultValue() {
return defaultValue;
}
/**
*
* @return the data type of the tenant configuration value. (e.g.
* Integer.class, String.class)
*/
public Class<?> getDataType() {
return dataType;
}
/**
* validates if a object matches the allowed data format of the
* corresponding key
*
* @param context
* application context
* @param value
* which will be validated
* @throws TenantConfigurationValidatorException
* is thrown, when object is invalid
*/
public void validate(final ApplicationContext context, final Object value) {
final TenantConfigurationValidator createdBean = context.getAutowireCapableBeanFactory().createBean(validator);
try {
createdBean.validate(value);
} finally {
context.getAutowireCapableBeanFactory().destroyBean(createdBean);
}
}
/**
* @param keyName
* name of the TenantConfigurationKey
* @return the TenantConfigurationKey with the name keyName
*/
public static TenantConfigurationKey fromKeyName(final String keyName) {
final Optional<TenantConfigurationKey> optKey = Arrays.stream(TenantConfigurationKey.values())
.filter(conf -> conf.getKeyName().equals(keyName)).findFirst();
if (optKey.isPresent()) {
return optKey.get();
}
throw new InvalidTenantConfigurationKeyException("The given configuration key name does not exist.");
}
}

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.tenancy.configuration.validator;
/**
* specific tenant configuration validator, which validates that the given value
* is a booleans.
*/
public class TenantConfigurationBooleanValidator implements TenantConfigurationValidator {
@Override
public Class<?> validateToClass() {
return Boolean.class;
}
}

View File

@@ -0,0 +1,67 @@
/**
* 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.tenancy.configuration.validator;
import java.time.Duration;
import java.time.format.DateTimeParseException;
import org.eclipse.hawkbit.ControllerPollProperties;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This class is used to validate, that the property is a String and that it is
* in the correct duration format.
*
*/
public class TenantConfigurationPollingDurationValidator implements TenantConfigurationValidator {
private final Duration minDuration;
private final Duration maxDuration;
/**
* Constructor.
*
* @param properties
* property accessor for poll configuration
*/
@Autowired
public TenantConfigurationPollingDurationValidator(final ControllerPollProperties properties) {
minDuration = DurationHelper.formattedStringToDuration(properties.getMinPollingTime());
maxDuration = DurationHelper.formattedStringToDuration(properties.getMaxPollingTime());
}
@Override
public void validate(final Object tenantConfigurationObject) {
TenantConfigurationValidator.super.validate(tenantConfigurationObject);
final String tenantConfigurationString = (String) tenantConfigurationObject;
final Duration tenantConfigurationValue;
try {
tenantConfigurationValue = DurationHelper.formattedStringToDuration(tenantConfigurationString);
} catch (final DateTimeParseException ex) {
throw new TenantConfigurationValidatorException(
String.format("The given configuration value is expected as a string in the format %s.",
DurationHelper.DURATION_FORMAT));
}
if (!DurationHelper.durationRangeValidator(minDuration, maxDuration).isWithinRange(tenantConfigurationValue)) {
throw new TenantConfigurationValidatorException(
String.format("The given configuration value is not in the allowed range from %s to %s.",
DurationHelper.durationToFormattedString(minDuration),
DurationHelper.durationToFormattedString(maxDuration)));
}
}
@Override
public Class<?> validateToClass() {
return String.class;
}
}

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.tenancy.configuration.validator;
/**
* specific tenant configuration validator, which validates Strings.
*/
public class TenantConfigurationStringValidator implements TenantConfigurationValidator {
@Override
public Class<?> validateToClass() {
return String.class;
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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.tenancy.configuration.validator;
/**
* base interface for clases which can validate tenant configuration values.
*
*/
public interface TenantConfigurationValidator {
/**
* validates the tenant configuration value
*
* @param tenantConfigurationValue
* value which will be validated.
* @throws TenantConfigurationValidatorException
* is thrown, when parameter is invalid.
*/
default void validate(final Object tenantConfigurationValue) throws TenantConfigurationValidatorException {
if (tenantConfigurationValue != null
&& validateToClass().isAssignableFrom(tenantConfigurationValue.getClass())) {
return;
}
throw new TenantConfigurationValidatorException(
"The given configuration value is expected as a " + validateToClass().getSimpleName());
}
/**
* Return the generic class to check the object
*
* @return the class to check the value
*/
default Class<?> validateToClass() {
return Object.class;
}
}

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