Initial check in accordance with Parallel IP
This commit is contained in:
105
3rd-dependencies/compile.txt
Executable file
105
3rd-dependencies/compile.txt
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
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
|
||||||
|
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-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
|
||||||
|
commons-io:commons-io:jar:2.4:compile
|
||||||
|
cz.jirutka.rsql:rsql-parser:jar:2.0.0: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
|
||||||
|
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.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.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.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.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.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.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
|
||||||
|
org.springframework.data:spring-data-redis:jar:1.5.1.RELEASE:compile
|
||||||
|
org.springframework.hateoas:spring-hateoas:jar:0.16.0.RELEASE:compile
|
||||||
|
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.vaadin.addons.lazyquerycontainer:vaadin-lazyquerycontainer:jar:7.4.0.1:compile
|
||||||
|
org.vaadin.addons:flexibleoptiongroup:jar:2.2.0:compile
|
||||||
|
org.vaadin.addons:tokenfield:jar:7.0.1: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
|
||||||
8
3rd-dependencies/listDeps.sh
Executable file
8
3rd-dependencies/listDeps.sh
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
# This script
|
||||||
|
cd ..
|
||||||
|
mvn dependency:list -DexcludeGroupIds=org.eclipse.hawkbit -Dsort=true -DoutputFile=dependencies.txt
|
||||||
|
find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:compile'|sort|uniq > 3rd-dependencies/compile.txt
|
||||||
|
find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:test'|sort|uniq > 3rd-dependencies/test.txt
|
||||||
|
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/
|
||||||
6
3rd-dependencies/provided.txt
Executable file
6
3rd-dependencies/provided.txt
Executable file
@@ -0,0 +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
|
||||||
55
3rd-dependencies/test.txt
Executable file
55
3rd-dependencies/test.txt
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
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
|
||||||
|
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
|
||||||
|
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.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.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
|
||||||
|
ru.yandex.qatools.properties:properties-loader:jar:1.5:test
|
||||||
70
CONTRUBUTING.md
Executable file
70
CONTRUBUTING.md
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
# Contributing to eclipse hawkBit
|
||||||
|
|
||||||
|
:+1: First off, thanks for taking the time to contribute! We really appreciate this. :+1:
|
||||||
|
|
||||||
|
Please read this if you intend to contribute to the project.
|
||||||
|
|
||||||
|
## Code Conventions
|
||||||
|
|
||||||
|
* Java files:
|
||||||
|
* we follow the standard eclipse IDE (built in) code formatter with the following changes:
|
||||||
|
* Tab policy: spaces only: 4
|
||||||
|
* XML files:
|
||||||
|
* we follow the standard eclipse IDE XML formatter with the following changes:
|
||||||
|
* Indent using spaces only: 3
|
||||||
|
* SCSS files:
|
||||||
|
* we follow the standard [scss-lint](https://github.com/brigade/scss-lint/) rules with the following exception:
|
||||||
|
* disabled rules: ImportantRule, PropertySortOrder
|
||||||
|
* Sonarqube:
|
||||||
|
* Our rule set is defined [here](http://sonar.eu-gb.mybluemix.net)
|
||||||
|
|
||||||
|
## Legal considerations for your contribution
|
||||||
|
|
||||||
|
The following steps are necessary to comply with the Eclipse Foundation's IP policy.
|
||||||
|
|
||||||
|
Please also read [this](http://wiki.eclipse.org/Development_Resources/Contributing_via_Git)
|
||||||
|
|
||||||
|
In order for any contributions to be accepted you MUST do the following things.
|
||||||
|
|
||||||
|
* Sign the [Eclipse Foundation Contributor License Agreement](http://www.eclipse.org/legal/CLA.php).
|
||||||
|
To sign the Eclipse CLA you need to:
|
||||||
|
|
||||||
|
* Obtain an Eclipse Foundation userid. Anyone who currently uses Eclipse Bugzilla or Gerrit systems already has one of those.
|
||||||
|
If you don’t, you need to [register](https://dev.eclipse.org/site_login/createaccount.php).
|
||||||
|
|
||||||
|
* Login into the [projects portal](https://projects.eclipse.org/), select “My Account”, and then the “Contributor License Agreement” tab.
|
||||||
|
|
||||||
|
* Add your github username in your Eclipse Foundation account settings. Log in it to Eclipse and go to account settings.
|
||||||
|
|
||||||
|
* "Sign-off" your commits (NOTE! This is only necessary if contributing to the vertx-core project)
|
||||||
|
|
||||||
|
Every commit you make in your patch or pull request MUST be "signed off".
|
||||||
|
|
||||||
|
You do this by adding the `-s` flag when you make the commit(s), e.g.
|
||||||
|
|
||||||
|
git commit -s -m "Shave the yak some more"
|
||||||
|
|
||||||
|
## Making your changes
|
||||||
|
|
||||||
|
* Fork the repository on GitHub
|
||||||
|
* Create a new branch for your changes
|
||||||
|
* Make your changes
|
||||||
|
* Make sure you include tests
|
||||||
|
* Make sure the tests pass after your changes
|
||||||
|
* Commit your changes into that branch
|
||||||
|
* Use descriptive and meaningful commit messages
|
||||||
|
* If you have a lot of commits squash them into a single commit
|
||||||
|
* Make sure you use the `-s` flag when committing as explained above.
|
||||||
|
* Push your changes to your branch in your forked repository
|
||||||
|
|
||||||
|
## Submitting the changes
|
||||||
|
|
||||||
|
Submit a pull request via the normal GitHub UI (desktop or web).
|
||||||
|
|
||||||
|
## After submitting
|
||||||
|
|
||||||
|
* Do not use your branch for any other development, otherwise further changes that you make will be visible in the PR.
|
||||||
|
|
||||||
|
# Further information
|
||||||
|
|
||||||
|
* [Eclipse Project Page](http://projects.eclipse.org/projects/iot.hawkbit)
|
||||||
131
DDIA.md
Executable file
131
DDIA.md
Executable file
@@ -0,0 +1,131 @@
|
|||||||
|
## 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
6
LICENCE_HEADER_TEMPLATE.txt
Executable file
6
LICENCE_HEADER_TEMPLATE.txt
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
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
|
||||||
37
README.md
Executable file
37
README.md
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
# hawkbit-update-server
|
||||||
|
Build Status: [](https://circleci.com/gh/bsinno/hawkbit-update-server/tree/master)
|
||||||
|
|
||||||
|
[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.
|
||||||
|
|
||||||
|
|
||||||
|
# Compile
|
||||||
|
```
|
||||||
|
mvn install
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
`hawkbit-security-integration` : security integration elements to integrate security into hawkbit.
|
||||||
|
`hawkbit-artifact-repository-mongo` : artifact repository implementation to mongoDB.
|
||||||
|
`hawkbit-autoconfigure` : spring-boot auto-configuration.
|
||||||
|
`hawkbit-dmf-api` : API for the Device Management Integration.
|
||||||
|
`hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API.
|
||||||
|
`hawkbit-repository` : repository implemenation based on SQL for all meta-data.
|
||||||
|
`hawkbit-http-security` : implementation for security filters for HTTP.
|
||||||
|
`hawkbit-rest-api` : API classes for the REST Management API.
|
||||||
|
`hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API.
|
||||||
|
`hawkbit-rest-resource` : 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)
|
||||||
33
circle.yml
Executable file
33
circle.yml
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
machine:
|
||||||
|
java:
|
||||||
|
version: oraclejdk8
|
||||||
|
environment:
|
||||||
|
_JAVA_OPTIONS: "-Xms512m -Xmx1024m"
|
||||||
|
dependencies:
|
||||||
|
cache_directories:
|
||||||
|
- "~/.embedmongo"
|
||||||
|
override:
|
||||||
|
- mvn install -DskipTests
|
||||||
|
test:
|
||||||
|
override:
|
||||||
|
- sh sonarCircleCi.sh
|
||||||
|
post:
|
||||||
|
- mkdir -p $CIRCLE_TEST_REPORTS/junit/
|
||||||
|
- find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
|
||||||
|
general:
|
||||||
|
artifacts:
|
||||||
|
- "*.jar"
|
||||||
|
- "pom.xml"
|
||||||
|
notify:
|
||||||
|
webhooks:
|
||||||
|
# gitter hook
|
||||||
|
- url: https://webhooks.gitter.im/e/a20a6bc2bda5a8a77d39
|
||||||
295
eclipse_codeformatter.xml
Executable file
295
eclipse_codeformatter.xml
Executable file
@@ -0,0 +1,295 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<profiles version="12">
|
||||||
|
<profile kind="CodeFormatterProfile" name="hawkBit" version="12">
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
2
examples/README.md
Executable file
2
examples/README.md
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
# Examples
|
||||||
|
TODO
|
||||||
2
examples/hawkbit-device-simulator/.gitignore
vendored
Executable file
2
examples/hawkbit-device-simulator/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
/bin/
|
||||||
|
/target/
|
||||||
18
examples/hawkbit-device-simulator/README.md
Executable file
18
examples/hawkbit-device-simulator/README.md
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
# hawkBit Device Simulator
|
||||||
|
|
||||||
|
The device simulator handles software update commands from the update server.
|
||||||
|
|
||||||
|
## Run
|
||||||
|
```
|
||||||
|
java -jar examples/hawkbit-device-simulator/target/hawkbit-device-simulator-*-SNAPSHOT.jar
|
||||||
|
```
|
||||||
|
Or:
|
||||||
|
```
|
||||||
|
run org.eclipse.hawkbit.simulator.DeviceSimulator
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
The device simulator exposes an REST-API which can be used to trigger device creation.
|
||||||
|
```
|
||||||
|
http://localhost:8083/start?amount=10
|
||||||
|
```
|
||||||
61
examples/hawkbit-device-simulator/pom.xml
Executable file
61
examples/hawkbit-device-simulator/pom.xml
Executable file
@@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.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
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
<artifactId>hawkbit-examples-parent</artifactId>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>hawkbit-device-simulator</artifactId>
|
||||||
|
<name>hawkBit :: Device Simulator</name>
|
||||||
|
<description>Device Management Federation API based simulator</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-dmf-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.amqp</groupId>
|
||||||
|
<artifactId>spring-rabbit</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-logging</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main-method to start the Spring-Boot application.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class DeviceSimulator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the Spring Boot Application.
|
||||||
|
*
|
||||||
|
* @param args
|
||||||
|
* the args
|
||||||
|
*/
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
SpringApplication.run(DeviceSimulator.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST endpoint for controlling the device simulator.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class SimulationController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SpSenderService spSenderService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start resource to start a device creation.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the name prefix of the generated device naming
|
||||||
|
* @param amount
|
||||||
|
* the amount of devices to be created
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to create the device to
|
||||||
|
* @return a response string that devices has been created
|
||||||
|
*/
|
||||||
|
@RequestMapping("/start")
|
||||||
|
String start(@RequestParam(value = "name", defaultValue = "dmfSimulated") final String name,
|
||||||
|
@RequestParam(value = "amount", defaultValue = "20") final int amount,
|
||||||
|
@RequestParam(value = "tenant", defaultValue = "DEFAULT") final String tenant) {
|
||||||
|
|
||||||
|
for (int i = 0; i < amount; i++) {
|
||||||
|
spSenderService.createOrUpdateThing(tenant, name + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Updated " + amount + " DMF connected targets!";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.amqp.core.Binding;
|
||||||
|
import org.springframework.amqp.core.BindingBuilder;
|
||||||
|
import org.springframework.amqp.core.FanoutExchange;
|
||||||
|
import org.springframework.amqp.core.Queue;
|
||||||
|
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
|
||||||
|
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||||
|
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
||||||
|
import org.springframework.amqp.support.converter.MessageConverter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The spring AMQP configuration to use a AMQP for communication with SP update
|
||||||
|
* server.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(AmqpProperties.class)
|
||||||
|
public class AmqpConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected AmqpProperties amqpProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConnectionFactory connectionFactory;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create jackson message converter bean.
|
||||||
|
*
|
||||||
|
* @return the jackson message converter
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MessageConverter jsonMessageConverter() {
|
||||||
|
final Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
|
||||||
|
rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter);
|
||||||
|
return jackson2JsonMessageConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the receiver queue from sp. Receive messages from sp.
|
||||||
|
*
|
||||||
|
* @return the queue
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Queue receiverConnectorQueueFromSp() {
|
||||||
|
return new Queue(amqpProperties.getReceiverConnectorQueueFromSp(), true, false, false,
|
||||||
|
getDeadLetterExchangeArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the recevier exchange. Sp send messages to this exchange.
|
||||||
|
*
|
||||||
|
* @return the exchange
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public FanoutExchange exchangeQueueToConnector() {
|
||||||
|
return new FanoutExchange(amqpProperties.getSenderForSpExchange());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Binding
|
||||||
|
* {@link AmqpConfiguration#receiverConnectorQueueFromSp()} to
|
||||||
|
* {@link AmqpConfiguration#exchangeQueueToConnector()}.
|
||||||
|
*
|
||||||
|
* @return the binding and create the queue and exchange
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Binding bindReceiverQueueToSpExchange() {
|
||||||
|
return BindingBuilder.bind(receiverConnectorQueueFromSp()).to(exchangeQueueToConnector());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create dead letter queue.
|
||||||
|
*
|
||||||
|
* @return the queue
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Queue deadLetterQueue() {
|
||||||
|
return new Queue(amqpProperties.getDeadLetterQueue(), true, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the dead letter fanout exchange.
|
||||||
|
*
|
||||||
|
* @return the fanout exchange
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public FanoutExchange exchangeDeadLetter() {
|
||||||
|
return new FanoutExchange(amqpProperties.getDeadLetterExchange());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Binding deadLetterQueue to exchangeDeadLetter.
|
||||||
|
*
|
||||||
|
* @return the binding
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Binding bindDeadLetterQueueToLwm2mExchange() {
|
||||||
|
return BindingBuilder.bind(deadLetterQueue()).to(exchangeDeadLetter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Listener factory.
|
||||||
|
*
|
||||||
|
* @return the {@link SimpleMessageListenerContainer} that gets used receive
|
||||||
|
* AMQP messages
|
||||||
|
*/
|
||||||
|
@Bean(name = { "listenerContainerFactory" })
|
||||||
|
public SimpleRabbitListenerContainerFactory listenerContainerFactory() {
|
||||||
|
final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
|
||||||
|
containerFactory.setDefaultRequeueRejected(false);
|
||||||
|
containerFactory.setConnectionFactory(connectionFactory);
|
||||||
|
return containerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getDeadLetterExchangeArgs() {
|
||||||
|
final Map<String, Object> args = new HashMap<String, Object>();
|
||||||
|
args.put("x-dead-letter-exchange", amqpProperties.getDeadLetterExchange());
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.simulator.amqp;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bean which holds the necessary properties for configuring the AMQP
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("hawkbit.device.simulator.amqp")
|
||||||
|
public class AmqpProperties {
|
||||||
|
|
||||||
|
private String receiverConnectorQueueFromSp;
|
||||||
|
private String senderForSpExchange;
|
||||||
|
|
||||||
|
private String deadLetterQueue;
|
||||||
|
private String deadLetterExchange;
|
||||||
|
|
||||||
|
public String getReceiverConnectorQueueFromSp() {
|
||||||
|
return receiverConnectorQueueFromSp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReceiverConnectorQueueFromSp(final String receiverConnectorQueueFromSp) {
|
||||||
|
this.receiverConnectorQueueFromSp = receiverConnectorQueueFromSp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeadLetterExchange() {
|
||||||
|
return deadLetterExchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeadLetterExchange(final String deadLetterExchange) {
|
||||||
|
this.deadLetterExchange = deadLetterExchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeadLetterQueue() {
|
||||||
|
return deadLetterQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeadLetterQueue(final String deadLetterQueue) {
|
||||||
|
this.deadLetterQueue = deadLetterQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSenderForSpExchange() {
|
||||||
|
return senderForSpExchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSenderForSpExchange(final String senderForSpExchange) {
|
||||||
|
this.senderForSpExchange = senderForSpExchange;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constants for the caching.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class MessageHandlerCacheConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the cache.
|
||||||
|
*/
|
||||||
|
public static final String CACHE_NAME = "hawkbit.device.simulator.states";
|
||||||
|
|
||||||
|
private MessageHandlerCacheConstant() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.amqp.core.Message;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.amqp.support.converter.AbstractJavaTypeMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for sender and receiver service.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MessageService {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
|
||||||
|
|
||||||
|
protected RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
protected AmqpProperties amqpProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param rabbitTemplate
|
||||||
|
* the rabbit template
|
||||||
|
* @param amqpProperties
|
||||||
|
* the amqp properties
|
||||||
|
* @param messageConverter
|
||||||
|
* the message converter
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
public MessageService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties) {
|
||||||
|
this.rabbitTemplate = rabbitTemplate;
|
||||||
|
this.amqpProperties = amqpProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmqpProperties(final AmqpProperties amqpProperties) {
|
||||||
|
this.amqpProperties = amqpProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRabbitTemplate(final RabbitTemplate rabbitTemplate) {
|
||||||
|
this.rabbitTemplate = rabbitTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to call when error emerges.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message that triggered the error
|
||||||
|
* @param error
|
||||||
|
* the error
|
||||||
|
*/
|
||||||
|
public void logAndThrowMessageError(final Message message, final String error) {
|
||||||
|
LOGGER.error("Error \"{}\" reported by message {}", error, message.getMessageProperties().getMessageId());
|
||||||
|
throw new IllegalArgumentException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a message body to a given class and set the message header
|
||||||
|
* AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME for Jackson converter.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* which body will converted
|
||||||
|
* @param clazz
|
||||||
|
* the body class
|
||||||
|
* @return the converted body
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T convertMessage(final Message message, final Class<T> clazz) {
|
||||||
|
message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME,
|
||||||
|
clazz.getTypeName());
|
||||||
|
return (T) rabbitTemplate.getMessageConverter().fromMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to verify if lwm2m header is set.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message with the header
|
||||||
|
* @param header
|
||||||
|
* the header to verify
|
||||||
|
*/
|
||||||
|
public void checkIfLwm2mHeaderEmpty(final Message message, final String header) {
|
||||||
|
final Object headerObject = message.getMessageProperties().getHeaders().get(header);
|
||||||
|
if (null == headerObject) {
|
||||||
|
logAndThrowMessageError(message, "Header of " + header + "empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
import org.springframework.amqp.core.Message;
|
||||||
|
import org.springframework.amqp.core.MessageProperties;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for all receiver objects.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class ReceiverService extends MessageService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param rabbitTemplate
|
||||||
|
* RabbitTemplate
|
||||||
|
* @param amqpProperties
|
||||||
|
* AmqpProperties
|
||||||
|
* @param messageConverter
|
||||||
|
* MessageConverter
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
public ReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties) {
|
||||||
|
super(rabbitTemplate, amqpProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to validate if content type is set in the message properties.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message to get validated
|
||||||
|
*/
|
||||||
|
protected void checkContentTypeJson(final Message message) {
|
||||||
|
if (message.getBody().length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final MessageProperties messageProperties = message.getMessageProperties();
|
||||||
|
final String headerContentType = (String) messageProperties.getHeaders().get("content-type");
|
||||||
|
if (null != headerContentType) {
|
||||||
|
messageProperties.setContentType(headerContentType);
|
||||||
|
}
|
||||||
|
final String contentType = messageProperties.getContentType();
|
||||||
|
if (contentType != null && contentType.contains("json")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Content-Type is not JSON compatible");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
import org.springframework.amqp.core.Message;
|
||||||
|
import org.springframework.amqp.core.MessageProperties;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract calls for sender service objects.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class SenderService extends MessageService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for sender service.
|
||||||
|
*
|
||||||
|
* @param rabbitTemplate
|
||||||
|
* the rabbit template
|
||||||
|
* @param amqpProperties
|
||||||
|
* the amqp properties
|
||||||
|
* @param cacheManager
|
||||||
|
* the cache manager
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
public SenderService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties) {
|
||||||
|
super(rabbitTemplate, amqpProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message if the message is not null.
|
||||||
|
*
|
||||||
|
* @param adress
|
||||||
|
* the exchange name
|
||||||
|
* @param message
|
||||||
|
* the amqp message which will be send if its not null
|
||||||
|
*/
|
||||||
|
public void sendMessage(final String adress, final Message message) {
|
||||||
|
if (message == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rabbitTemplate.setExchange(adress);
|
||||||
|
rabbitTemplate.send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert object and message properties to message.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* to get converted
|
||||||
|
* @param messageProperties
|
||||||
|
* to get converted
|
||||||
|
* @return converted message
|
||||||
|
*/
|
||||||
|
public Message convertMessage(final Object object, final MessageProperties messageProperties) {
|
||||||
|
return rabbitTemplate.getMessageConverter().toMessage(object, messageProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object for holding attributes for a simulated update for the device
|
||||||
|
* simulator.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SimulatedUpdate implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
protected final String tenant;
|
||||||
|
protected final String thingId;
|
||||||
|
|
||||||
|
protected final Long actionId;
|
||||||
|
|
||||||
|
protected LocalDateTime startCacheTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of the class.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant name.
|
||||||
|
* @param thingId
|
||||||
|
* the thing id.
|
||||||
|
* @param actionId
|
||||||
|
* the action id
|
||||||
|
* @param softwareModuleId
|
||||||
|
* software modul id
|
||||||
|
* @param urls
|
||||||
|
* the artifact download urls.
|
||||||
|
*/
|
||||||
|
public SimulatedUpdate(final String tenant, final String thingId, final Long actionId) {
|
||||||
|
this.tenant = tenant;
|
||||||
|
this.thingId = thingId;
|
||||||
|
this.actionId = actionId;
|
||||||
|
this.startCacheTime = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTenant() {
|
||||||
|
return tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getThingId() {
|
||||||
|
return thingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getActionId() {
|
||||||
|
return actionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getStartCacheTime() {
|
||||||
|
return startCacheTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
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.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.amqp.core.Message;
|
||||||
|
import org.springframework.amqp.core.MessageProperties;
|
||||||
|
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.messaging.handler.annotation.Header;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle all incoming Messages from SP.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SpReceiverService extends ReceiverService {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ReceiverService.class);
|
||||||
|
|
||||||
|
public static final String SOFTWARE_MODULE_FIRMWARE = "firmware";
|
||||||
|
|
||||||
|
private final SpSenderService spSenderService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param rabbitTemplate
|
||||||
|
* the rabbit template
|
||||||
|
* @param amqpProperties
|
||||||
|
* the amqp properties
|
||||||
|
* @param lwm2mSenderService
|
||||||
|
* the lwm2mSenderService
|
||||||
|
* @param spSenderService
|
||||||
|
* the spSenderService
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties,
|
||||||
|
final SpSenderService spSenderService) {
|
||||||
|
super(rabbitTemplate, amqpProperties);
|
||||||
|
this.spSenderService = spSenderService;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the incoming Message from Queue with the property
|
||||||
|
* (com.bosch.sp.lwm2m.connector.amqp.receiverConnectorQueueFromSp).
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the incoming message
|
||||||
|
* @param type
|
||||||
|
* the action type
|
||||||
|
* @param contentType
|
||||||
|
* the content type in message header
|
||||||
|
* @param thingId
|
||||||
|
* the thing id in message header
|
||||||
|
*/
|
||||||
|
@RabbitListener(queues = "${hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp}", containerFactory = "listenerContainerFactory")
|
||||||
|
public void recieveMessageSp(final Message message, @Header(MessageHeaderKey.TYPE) final String type,
|
||||||
|
@Header(MessageHeaderKey.THING_ID) final String thingId) {
|
||||||
|
checkContentTypeJson(message);
|
||||||
|
delegateMessage(message, type, thingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void delegateMessage(final Message message, final String type, final String thingId) {
|
||||||
|
final MessageType messageType = MessageType.valueOf(type);
|
||||||
|
|
||||||
|
switch (messageType) {
|
||||||
|
case EVENT:
|
||||||
|
handleEventMessage(message, thingId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGGER.info("No valid message type property.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleEventMessage(final Message message, final String thingId) {
|
||||||
|
final Object eventHeader = message.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC);
|
||||||
|
if (eventHeader == null) {
|
||||||
|
logAndThrowMessageError(message, "Event Topic is not set");
|
||||||
|
}
|
||||||
|
final EventTopic eventTopic = EventTopic.valueOf(eventHeader.toString());
|
||||||
|
switch (eventTopic) {
|
||||||
|
case DOWNLOAD_AND_INSTALL:
|
||||||
|
handleUpdateProcess(message, thingId);
|
||||||
|
break;
|
||||||
|
case CANCEL_DOWNLOAD:
|
||||||
|
handleCancelDownloadAction(message, thingId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGGER.info("No valid event property.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCancelDownloadAction(final Message message, final String thingId) {
|
||||||
|
final MessageProperties messageProperties = message.getMessageProperties();
|
||||||
|
final Map<String, Object> headers = messageProperties.getHeaders();
|
||||||
|
final String tenant = (String) headers.get(MessageHeaderKey.TENANT);
|
||||||
|
final Long actionId = convertMessage(message, Long.class);
|
||||||
|
|
||||||
|
final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId);
|
||||||
|
spSenderService.finishUpdateProcess(update, "Simulation canceled");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUpdateProcess(final Message message, final String thingId) {
|
||||||
|
final MessageProperties messageProperties = message.getMessageProperties();
|
||||||
|
final Map<String, Object> headers = messageProperties.getHeaders();
|
||||||
|
final String tenant = (String) headers.get(MessageHeaderKey.TENANT);
|
||||||
|
|
||||||
|
final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message,
|
||||||
|
DownloadAndUpdateRequest.class);
|
||||||
|
final Long actionId = downloadAndUpdateRequest.getActionId();
|
||||||
|
|
||||||
|
spSenderService.sendActionStatusMessage(tenant, ActionStatus.RUNNING,
|
||||||
|
"device Simulator retrieved update request. proceeding with simulation.", actionId);
|
||||||
|
|
||||||
|
final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId);
|
||||||
|
|
||||||
|
spSenderService.finishUpdateProcess(update, "Simulation complete!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
|
||||||
|
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.ActionUpdateStatus;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.amqp.core.Message;
|
||||||
|
import org.springframework.amqp.core.MessageProperties;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sender service to send message to SP.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SpSenderService extends SenderService {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(SpSenderService.class);
|
||||||
|
|
||||||
|
private final String spExchange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param rabbitTemplate
|
||||||
|
* the rabbit template
|
||||||
|
* @param amqpProperties
|
||||||
|
* the amqp properties
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
public SpSenderService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties) {
|
||||||
|
super(rabbitTemplate, amqpProperties);
|
||||||
|
this.spExchange = AmqpSettings.DMF_EXCHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the update process. This will send a action status to SP.
|
||||||
|
*
|
||||||
|
* @param update
|
||||||
|
* the simulated update object
|
||||||
|
* @param description
|
||||||
|
* a description according the update process
|
||||||
|
*/
|
||||||
|
public void finishUpdateProcess(final SimulatedUpdate update, final String description) {
|
||||||
|
final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED, description);
|
||||||
|
sendMessage(spExchange, updateResultMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish update process with error and send error to SP.
|
||||||
|
*
|
||||||
|
* @param update
|
||||||
|
* the simulated update object
|
||||||
|
* @param messageDescription
|
||||||
|
* a description according the update process
|
||||||
|
*/
|
||||||
|
public void finishUpdateProcessWithError(final SimulatedUpdate update, final String messageDescription) {
|
||||||
|
sendErrorgMessage(update, messageDescription);
|
||||||
|
LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", messageDescription,
|
||||||
|
update.getThingId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an error message to SP.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant
|
||||||
|
* @param messageDescription
|
||||||
|
* the error message description to send
|
||||||
|
* @param actionId
|
||||||
|
* the ID of the action for the error message
|
||||||
|
*/
|
||||||
|
public void sendErrorMessage(final String tenant, final String messageDescription, final Long actionId) {
|
||||||
|
final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, messageDescription, actionId);
|
||||||
|
sendMessage(spExchange, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a warning message to SP.
|
||||||
|
*
|
||||||
|
* @param update
|
||||||
|
* the simulated update object
|
||||||
|
* @param warningMessage
|
||||||
|
* a warning description
|
||||||
|
*/
|
||||||
|
public void sendWarningMessage(final SimulatedUpdate update, final String warningMessage) {
|
||||||
|
final Message message = createActionStatusMessage(update, warningMessage, ActionStatus.WARNING);
|
||||||
|
sendMessage(spExchange, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to send a action status to SP.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant
|
||||||
|
* @param actionStatus
|
||||||
|
* the action status
|
||||||
|
* @param actionMessage
|
||||||
|
* the message to get send
|
||||||
|
* @param actionId
|
||||||
|
* the cached value
|
||||||
|
*/
|
||||||
|
public void sendActionStatusMessage(final String tenant, final ActionStatus actionStatus,
|
||||||
|
final String actionMessage, final Long actionId) {
|
||||||
|
final Message message = createActionStatusMessage(tenant, actionStatus, actionMessage, actionId);
|
||||||
|
sendMessage(message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new thing created message and send to SP.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to create the target
|
||||||
|
* @param targetId
|
||||||
|
* the ID of the target to create or update
|
||||||
|
*/
|
||||||
|
public void createOrUpdateThing(final String tenant, final String targetId) {
|
||||||
|
|
||||||
|
final MessageProperties messagePropertiesForSP = new MessageProperties();
|
||||||
|
messagePropertiesForSP.setHeader(MessageHeaderKey.TYPE, MessageType.THING_CREATED.name());
|
||||||
|
messagePropertiesForSP.setHeader(MessageHeaderKey.TENANT, tenant);
|
||||||
|
messagePropertiesForSP.setHeader(MessageHeaderKey.THING_ID, targetId);
|
||||||
|
messagePropertiesForSP.setHeader(MessageHeaderKey.SENDER, "simulator");
|
||||||
|
messagePropertiesForSP.setContentType(MessageProperties.CONTENT_TYPE_JSON);
|
||||||
|
messagePropertiesForSP.setReplyTo(amqpProperties.getSenderForSpExchange());
|
||||||
|
final Message convertedMessage = new Message(null, messagePropertiesForSP);
|
||||||
|
sendMessage(spExchange, convertedMessage);
|
||||||
|
LOGGER.debug("Created thing created message and send to SP for Thing \"{}\"", targetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a created message to SP.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message to get send
|
||||||
|
*/
|
||||||
|
private void sendMessage(final Message message) {
|
||||||
|
sendMessage(spExchange, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send error message to SP.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* the current context
|
||||||
|
* @param messageDescription
|
||||||
|
* a description according the update process
|
||||||
|
*/
|
||||||
|
private void sendErrorgMessage(final SimulatedUpdate update, final String messageDescription) {
|
||||||
|
final Message message = createActionStatusMessage(update, messageDescription, ActionStatus.ERROR);
|
||||||
|
sendMessage(spExchange, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a action status message.
|
||||||
|
*
|
||||||
|
* @param actionStatus
|
||||||
|
* the ActionStatus
|
||||||
|
* @param actionMessage
|
||||||
|
* the message description
|
||||||
|
* @param actionId
|
||||||
|
* the action id
|
||||||
|
* @param cacheValue
|
||||||
|
* the cacheValue value
|
||||||
|
*/
|
||||||
|
private Message createActionStatusMessage(final String tenant, final ActionStatus actionStatus,
|
||||||
|
final String actionMessage, final Long actionId) {
|
||||||
|
final MessageProperties messageProperties = new MessageProperties();
|
||||||
|
final Map<String, Object> headers = messageProperties.getHeaders();
|
||||||
|
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
|
||||||
|
actionUpdateStatus.setActionStatus(actionStatus);
|
||||||
|
headers.put(MessageHeaderKey.TYPE, MessageType.EVENT.name());
|
||||||
|
headers.put(MessageHeaderKey.TENANT, tenant);
|
||||||
|
headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
|
||||||
|
headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON);
|
||||||
|
if (!StringUtils.isEmpty(actionMessage)) {
|
||||||
|
actionUpdateStatus.getMessage().add(actionMessage);
|
||||||
|
}
|
||||||
|
actionUpdateStatus.setActionId(actionId);
|
||||||
|
return convertMessage(actionUpdateStatus, messageProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message createUpdateResultMessage(final SimulatedUpdate cacheValue, final ActionStatus actionStatus,
|
||||||
|
final String updateResultMessage) {
|
||||||
|
final MessageProperties messageProperties = new MessageProperties();
|
||||||
|
final Map<String, Object> headers = messageProperties.getHeaders();
|
||||||
|
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
|
||||||
|
actionUpdateStatus.setActionStatus(actionStatus);
|
||||||
|
headers.put(MessageHeaderKey.TYPE, MessageType.EVENT.name());
|
||||||
|
headers.put(MessageHeaderKey.TENANT, cacheValue.getTenant());
|
||||||
|
headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
|
||||||
|
headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON);
|
||||||
|
actionUpdateStatus.getMessage().add(updateResultMessage);
|
||||||
|
actionUpdateStatus.setActionId(cacheValue.getActionId());
|
||||||
|
return convertMessage(actionUpdateStatus, messageProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message createActionStatusMessage(final SimulatedUpdate update, final String messageDescription,
|
||||||
|
final ActionStatus status) {
|
||||||
|
final Message sendMessage = createActionStatusMessage(update.getTenant(), status, messageDescription,
|
||||||
|
update.getActionId());
|
||||||
|
return sendMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
101
examples/hawkbit-device-simulator/src/main/resources/application.properties
Executable file
101
examples/hawkbit-device-simulator/src/main/resources/application.properties
Executable 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
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
#########################################################################################
|
||||||
|
# PUBLIC configuration, i.e. can be changed by users at runtime (defaults provided here)
|
||||||
|
#########################################################################################
|
||||||
|
## Configuration for RabbitMQ communication
|
||||||
|
hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp=sp_connector_receiver
|
||||||
|
hawkbit.device.simulator.amqp.deadLetterQueue=simulator_deadletter
|
||||||
|
hawkbit.device.simulator.amqp.deadLetterExchange=simulator.deadletter
|
||||||
|
hawkbit.device.simulator.amqp.senderForSpExchange=simulator.replyTo
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration for RabbitMQ integration
|
||||||
|
spring.rabbitmq.username=guest
|
||||||
|
spring.rabbitmq.password=guest
|
||||||
|
spring.rabbitmq.virtualHost=/
|
||||||
|
spring.rabbitmq.host=localhost
|
||||||
|
spring.rabbitmq.port=5672
|
||||||
|
spring.rabbitmq.dynamic=true
|
||||||
|
|
||||||
|
|
||||||
|
#disable expose jmx beans
|
||||||
|
spring.jmx.enabled=false
|
||||||
|
# the context path of the monitor spring actuator which offers following endpoints
|
||||||
|
# /autoconfig, /beans, /configprops, /dump, /env, /health, /info, /metrics, /mappings, /trace
|
||||||
|
management.context-path=/system
|
||||||
|
management.security.enabled=true
|
||||||
|
management.security.sessions=stateless
|
||||||
|
# ENDPOINTS
|
||||||
|
endpoints.autoconfig.id=autoconfig
|
||||||
|
endpoints.autoconfig.sensitive=true
|
||||||
|
endpoints.autoconfig.enabled=false
|
||||||
|
endpoints.beans.id=beans
|
||||||
|
endpoints.beans.sensitive=true
|
||||||
|
endpoints.beans.enabled=false
|
||||||
|
endpoints.configprops.id=configprops
|
||||||
|
endpoints.configprops.sensitive=true
|
||||||
|
endpoints.configprops.enabled=true
|
||||||
|
#endpoints.configprops.keys-to-sanitize=password,secret,key # suffix or regex
|
||||||
|
endpoints.dump.id=dump
|
||||||
|
endpoints.dump.sensitive=true
|
||||||
|
endpoints.dump.enabled=false
|
||||||
|
endpoints.env.id=env
|
||||||
|
endpoints.env.sensitive=true
|
||||||
|
endpoints.env.enabled=true
|
||||||
|
#endpoints.env.keys-to-sanitize=password,secret,key # suffix or regex
|
||||||
|
endpoints.health.id=health
|
||||||
|
endpoints.health.sensitive=true
|
||||||
|
endpoints.health.enabled=true
|
||||||
|
endpoints.info.id=info
|
||||||
|
endpoints.info.sensitive=true
|
||||||
|
endpoints.info.enabled=true
|
||||||
|
endpoints.metrics.id=metrics
|
||||||
|
endpoints.metrics.sensitive=true
|
||||||
|
endpoints.metrics.enabled=true
|
||||||
|
endpoints.shutdown.id=shutdown
|
||||||
|
endpoints.shutdown.sensitive=true
|
||||||
|
endpoints.shutdown.enabled=false
|
||||||
|
endpoints.trace.id=trace
|
||||||
|
endpoints.trace.sensitive=true
|
||||||
|
endpoints.trace.enabled=true
|
||||||
|
|
||||||
|
# HEALTH INDICATORS (previously health.*)
|
||||||
|
management.health.db.enabled=true
|
||||||
|
management.health.diskspace.enabled=true
|
||||||
|
management.health.mongo.enabled=true
|
||||||
|
management.health.rabbit.enabled=true
|
||||||
|
management.health.redis.enabled=false
|
||||||
|
management.health.solr.enabled=false
|
||||||
|
management.health.diskspace.path=.
|
||||||
|
management.health.diskspace.threshold=10485760
|
||||||
|
management.health.status.order=DOWN, OUT_OF_SERVICE, UNKNOWN, UP
|
||||||
|
|
||||||
|
# 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= /system/**
|
||||||
|
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=
|
||||||
|
|
||||||
|
server.port=8083
|
||||||
1
examples/hawkbit-example-app/.gitignore
vendored
Executable file
1
examples/hawkbit-example-app/.gitignore
vendored
Executable file
@@ -0,0 +1 @@
|
|||||||
|
/target/
|
||||||
15
examples/hawkbit-example-app/README.md
Executable file
15
examples/hawkbit-example-app/README.md
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
# hawkBit Example Application
|
||||||
|
The hawkBit example application is a standalone spring-boot application with an embedded servlet container to start the hawkBit.
|
||||||
|
|
||||||
|
## Run
|
||||||
|
```
|
||||||
|
java -jar examples/hawkbit-example-app/target/hawkbit-example-app-*-SNAPSHOT.jar
|
||||||
|
```
|
||||||
|
Or:
|
||||||
|
```
|
||||||
|
run org eclipse.hawkbit.app.Start
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
The UI can be accessed via _http://localhost:8080/UI_.
|
||||||
|
The REST API can be accessed via _http://localhost:8080/rest/v1_.
|
||||||
105
examples/hawkbit-example-app/pom.xml
Executable file
105
examples/hawkbit-example-app/pom.xml
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
|
||||||
|
All rights reserved. This program and the accompanying materials
|
||||||
|
are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
which accompanies this distribution, and is available at
|
||||||
|
http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-examples-parent</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>hawkbit-example-app</artifactId>
|
||||||
|
<name>hawkBit :: Example App</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.app.Start</mainClass>
|
||||||
|
<layout>JAR</layout>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Hawkbit -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-autoconfigure</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-dmf-amqp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-ui</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-security-integration</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-http-security</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-logging</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-aspects</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.app;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.ui.login.HawkbitLoginUI;
|
||||||
|
import org.eclipse.hawkbit.ui.themes.HawkbitTheme;
|
||||||
|
|
||||||
|
import com.vaadin.spring.annotation.SpringUI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example hawkBit login UI implementation.
|
||||||
|
*
|
||||||
|
* A {@link SpringUI} annotated class must be present in the classpath for the
|
||||||
|
* login path. The easiest way to get an hawkBit login UI running is to extend
|
||||||
|
* the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in
|
||||||
|
* this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SpringUI(path = HawkbitTheme.LOGIN_UI_PATH)
|
||||||
|
public class MyLoginUI extends HawkbitLoginUI {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
77
examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java
Executable file
77
examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java
Executable 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.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 com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example hawkBit UI implementation.
|
||||||
|
*
|
||||||
|
* A {@link SpringUI} annotated class must be present in the classpath. The
|
||||||
|
* easiest way to get an hawkBit UI running is to extend the {@link HawkbitUI}
|
||||||
|
* and to annotated it with {@link SpringUI} as in this example.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SpringUI
|
||||||
|
@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET)
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.app;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.RepositoryApplicationConfiguration;
|
||||||
|
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SpringBootApplication} annoated class with a main method to start.
|
||||||
|
* The minimal configuration for the standalone hawkBit server.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
@Import({ RepositoryApplicationConfiguration.class })
|
||||||
|
@EnableHawkbitManagedSecurityConfiguration
|
||||||
|
public class Start {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main method to start the spring-boot application.
|
||||||
|
*
|
||||||
|
* @param args
|
||||||
|
* the VM arguments.
|
||||||
|
*/
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
SpringApplication.run(Start.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
examples/hawkbit-example-app/src/main/resources/application.properties
Executable file
29
examples/hawkbit-example-app/src/main/resources/application.properties
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
#
|
||||||
|
# All rights reserved. This program and the accompanying materials
|
||||||
|
# are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
# which accompanies this distribution, and is available at
|
||||||
|
# http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
#
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
spring.profiles.active=amqp
|
||||||
|
|
||||||
|
vaadin.servlet.params.productionMode=false
|
||||||
|
vaadin.static.servlet.params.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
|
||||||
30
examples/pom.xml
Executable file
30
examples/pom.xml
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
|
||||||
|
All rights reserved. This program and the accompanying materials
|
||||||
|
are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
which accompanies this distribution, and is available at
|
||||||
|
http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-parent</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>hawkbit-examples-parent</artifactId>
|
||||||
|
<name>hawkBit :: Examples Parent</name>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>hawkbit-device-simulator</module>
|
||||||
|
<module>hawkbit-example-app</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
</project>
|
||||||
3
hawkbit-artifact-repository-mongo/README.md
Executable file
3
hawkbit-artifact-repository-mongo/README.md
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
# HawkBit Artifact Repositoy
|
||||||
|
HawkBit Artifact Repository is library for storing binary artifacts and metadata into MongoDB.
|
||||||
|
It has an spring-boot autoconfiguration for easily integration into spring-boot projects.
|
||||||
83
hawkbit-artifact-repository-mongo/pom.xml
Executable file
83
hawkbit-artifact-repository-mongo/pom.xml
Executable file
@@ -0,0 +1,83 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
|
||||||
|
All rights reserved. This program and the accompanying materials
|
||||||
|
are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
which accompanies this distribution, and is available at
|
||||||
|
http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
<artifactId>hawkbit-parent</artifactId>
|
||||||
|
</parent>
|
||||||
|
<artifactId>hawkbit-artifact-repository-mongo</artifactId>
|
||||||
|
<name>hawkBit :: Artifact Repository Mongo</name>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.data</groupId>
|
||||||
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>18.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- TEST -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.easytesting</groupId>
|
||||||
|
<artifactId>fest-assert-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.yandex.qatools.allure</groupId>
|
||||||
|
<artifactId>allure-junit-adaptor</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- MongoDB -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.flapdoodle.embed</groupId>
|
||||||
|
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Mockito -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact.repository;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.DigestOutputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||||
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.data.mongodb.gridfs.GridFsOperations;
|
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.MongoClientException;
|
||||||
|
import com.mongodb.MongoException;
|
||||||
|
import com.mongodb.gridfs.GridFSDBFile;
|
||||||
|
import com.mongodb.gridfs.GridFSFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file management which looks up all the file in the filestore.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ArtifactStore implements ArtifactRepository {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactStore.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mongoDB field which holds the filename of the file to download. SP
|
||||||
|
* Server uses the SHA hash as a filename and lookup in the mongoDB.
|
||||||
|
*/
|
||||||
|
private static final String FILENAME = "filename";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mongoDB field which automatically calculated by the mongoDB.
|
||||||
|
*/
|
||||||
|
private static final String MD5 = "md5";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mongoDB field which holds the SHA1 hash, stored in the metadata
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
private static final String SHA1 = "sha1";
|
||||||
|
|
||||||
|
private static final String ID = "_id";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GridFsOperations gridFs;
|
||||||
|
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a {@link GridFSDBFile} from the store by it's SHA1 hash.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to retrieve the artifacts from, ignore case.
|
||||||
|
* @param sha1Hash
|
||||||
|
* the sha1-hash of the file to lookup.
|
||||||
|
* @return The gridfs file object or {@code null} if no file exists.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DbArtifact getArtifactBySha1(final String sha1Hash) {
|
||||||
|
return map(gridFs.findOne(new Query().addCriteria(Criteria.where(FILENAME).is(sha1Hash))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a {@link GridFSDBFile} from the store by it's MD5 hash.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to retrieve the artifacts from, ignore case.
|
||||||
|
* @param md5Hash
|
||||||
|
* the md5-hash of the file to lookup.
|
||||||
|
* @return The gridfs file object or {@code null} if no file exists.
|
||||||
|
*/
|
||||||
|
public DbArtifact getArtifactByMd5(final String md5Hash) {
|
||||||
|
return map(gridFs.findOne(new Query().addCriteria(Criteria.where(MD5).is(md5Hash))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a {@link GridFSDBFile} from the store by it's object id.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to retrieve the artifacts from, ignore case.
|
||||||
|
* @param id
|
||||||
|
* the id of the file to lookup.
|
||||||
|
* @return The gridfs file object or {@code null} if no file exists.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DbArtifact getArtifactById(final String id) {
|
||||||
|
return map(gridFs.findOne(new Query().addCriteria(Criteria.where(ID).is(id))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DbArtifact store(final InputStream content, final String filename, final String contentType) {
|
||||||
|
return store(content, filename, contentType, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DbArtifact store(final InputStream content, final String filename, final String contentType,
|
||||||
|
final DbArtifactHash hash) {
|
||||||
|
File tempFile = null;
|
||||||
|
try {
|
||||||
|
LOGGER.debug("storing file {} of content {}", filename, contentType);
|
||||||
|
tempFile = File.createTempFile("uploadFile", null);
|
||||||
|
try (final FileOutputStream os = new FileOutputStream(tempFile)) {
|
||||||
|
return store(content, contentType, os, tempFile, hash);
|
||||||
|
}
|
||||||
|
} catch (final IOException | MongoException e1) {
|
||||||
|
throw new ArtifactStoreException(e1.getMessage(), e1);
|
||||||
|
} finally {
|
||||||
|
if (tempFile != null && !tempFile.delete()) {
|
||||||
|
LOGGER.error("Could not delete temporary file: {}", tempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteById(final String artifactId) {
|
||||||
|
try {
|
||||||
|
deleteArtifact(gridFs.findOne(new Query().addCriteria(Criteria.where(ID).is(artifactId))));
|
||||||
|
} catch (final MongoException e) {
|
||||||
|
throw new ArtifactStoreException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteBySha1(final String sha1Hash) {
|
||||||
|
try {
|
||||||
|
deleteArtifact(gridFs.findOne(new Query().addCriteria(Criteria.where(FILENAME).is(sha1Hash))));
|
||||||
|
} catch (final MongoException e) {
|
||||||
|
throw new ArtifactStoreException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteArtifact(final GridFSDBFile dbFile) {
|
||||||
|
if (dbFile != null) {
|
||||||
|
try {
|
||||||
|
gridFs.delete(new Query().addCriteria(Criteria.where(ID).is(dbFile.getId())));
|
||||||
|
} catch (final MongoClientException e) {
|
||||||
|
throw new ArtifactStoreException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private DbArtifact store(final InputStream content, final String contentType, final FileOutputStream os,
|
||||||
|
final File tempFile, final DbArtifactHash hash) {
|
||||||
|
final GridFsArtifact storedArtifact;
|
||||||
|
try {
|
||||||
|
final String sha1Hash = computeSHA1Hash(content, os, hash != null ? hash.getSha1() : null);
|
||||||
|
// upload if it does not exist already, check if file exists, not
|
||||||
|
// tenant specific.
|
||||||
|
final GridFSDBFile result = gridFs.findOne(new Query().addCriteria(Criteria.where(FILENAME).is(sha1Hash)));
|
||||||
|
if (null == result) {
|
||||||
|
try (FileInputStream inputStream = new FileInputStream(tempFile)) {
|
||||||
|
final BasicDBObject metadata = new BasicDBObject();
|
||||||
|
metadata.put(SHA1, sha1Hash);
|
||||||
|
storedArtifact = map(gridFs.store(inputStream, sha1Hash, contentType, metadata));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.info("file with sha1 hash {} already exists in database, increase reference counter", sha1Hash);
|
||||||
|
result.save();
|
||||||
|
storedArtifact = map(result);
|
||||||
|
}
|
||||||
|
} catch (final NoSuchAlgorithmException | IOException e) {
|
||||||
|
throw new ArtifactStoreException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hash != null && hash.getMd5() != null && !storedArtifact.getHashes().getMd5().equals(hash.getMd5())) {
|
||||||
|
throw new HashNotMatchException("The given md5 hash " + hash.getMd5()
|
||||||
|
+ " not matching the calculated md5 hash " + storedArtifact.getHashes().getMd5(),
|
||||||
|
HashNotMatchException.MD5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return storedArtifact;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String computeSHA1Hash(final InputStream stream, final FileOutputStream os, final String providedSHA1Sum)
|
||||||
|
throws NoSuchAlgorithmException, IOException {
|
||||||
|
String sha1Hash;
|
||||||
|
// compute digest
|
||||||
|
final MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||||
|
final DigestOutputStream dos = new DigestOutputStream(os, md);
|
||||||
|
ByteStreams.copy(stream, dos);
|
||||||
|
dos.close();
|
||||||
|
sha1Hash = BaseEncoding.base16().lowerCase().encode(md.digest());
|
||||||
|
if (providedSHA1Sum != null && !providedSHA1Sum.equalsIgnoreCase(sha1Hash)) {
|
||||||
|
throw new HashNotMatchException(
|
||||||
|
"The given sha1 hash " + providedSHA1Sum + " not matching the calculated sha1 hash " + sha1Hash,
|
||||||
|
HashNotMatchException.SHA1);
|
||||||
|
}
|
||||||
|
return sha1Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a list of {@link GridFSDBFile} to paged list of {@link DbArtifact}s.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant
|
||||||
|
* @param dbFiles
|
||||||
|
* the list of mongoDB gridFs files.
|
||||||
|
* @return a paged list of artifacts mapped from the given dbFiles
|
||||||
|
*/
|
||||||
|
private List<DbArtifact> map(final List<GridFSDBFile> dbFiles) {
|
||||||
|
final List<DbArtifact> collect = dbFiles.stream().map(dbFile -> map(dbFile)).collect(Collectors.toList());
|
||||||
|
return collect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of {@link GridFSDBFile} from the store by all SHA1
|
||||||
|
* hashes.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to retrieve the artifacts from, ignore case.
|
||||||
|
* @param sha1Hashes
|
||||||
|
* the sha1-hashes of the files to lookup.
|
||||||
|
* @return list of artfiacts
|
||||||
|
*/
|
||||||
|
public List<DbArtifact> getArtifactsBySha1(final List<String> sha1Hashes) {
|
||||||
|
return map(gridFs.find(new Query().addCriteria(Criteria.where(SHA1).in(sha1Hashes))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of {@link GridFSDBFile} from the store by all ids.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to retrieve the artifacts from, ignore case.
|
||||||
|
* @param ids
|
||||||
|
* the ids of the files to lookup.
|
||||||
|
* @return list of artfiacts
|
||||||
|
*/
|
||||||
|
public List<DbArtifact> getArtifactsByIds(final List<String> ids) {
|
||||||
|
return map(gridFs.find(new Query().addCriteria(Criteria.where(ID).in(ids))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a single {@link GridFSFile} to {@link DbArtifact}.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant
|
||||||
|
* @param dbFile
|
||||||
|
* the mongoDB gridFs file.
|
||||||
|
* @return a mapped artifact from the given dbFile
|
||||||
|
*/
|
||||||
|
private GridFsArtifact map(final GridFSFile fsFile) {
|
||||||
|
if (fsFile == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final GridFsArtifact artifact = new GridFsArtifact(fsFile);
|
||||||
|
artifact.setArtifactId(fsFile.getId().toString());
|
||||||
|
artifact.setSize(fsFile.getLength());
|
||||||
|
artifact.setContentType(fsFile.getContentType());
|
||||||
|
artifact.setHashes(new DbArtifactHash(fsFile.getFilename(), fsFile.getMD5()));
|
||||||
|
return artifact;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.artifact.repository;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto configuration for the {@link ArtifactStore}.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan
|
||||||
|
@ConditionalOnMissingBean(value = ArtifactRepository.class)
|
||||||
|
@Import(value = MongoConfiguration.class)
|
||||||
|
public class ArtifactStoreAutoConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Default {@link ArtifactRepository} implementation.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public ArtifactRepository artifactRepository() {
|
||||||
|
return new ArtifactStore();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.artifact.repository;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||||
|
|
||||||
|
import com.mongodb.gridfs.GridFSDBFile;
|
||||||
|
import com.mongodb.gridfs.GridFSFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper object for the {@link DbArtifact} object which returns the
|
||||||
|
* {@link InputStream} directly from {@link GridFSDBFile#getInputStream()} which
|
||||||
|
* retrieves when calling {@link #getFileInputStream()} always a new
|
||||||
|
* {@link InputStream} and not the same.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class GridFsArtifact extends DbArtifact {
|
||||||
|
|
||||||
|
private final GridFSFile dbFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param dbFile
|
||||||
|
*/
|
||||||
|
public GridFsArtifact(final GridFSFile dbFile) {
|
||||||
|
this.dbFile = dbFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getFileInputStream() {
|
||||||
|
if (dbFile instanceof GridFSDBFile) {
|
||||||
|
return ((GridFSDBFile) dbFile).getInputStream();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact.repository;
|
||||||
|
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
|
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
|
||||||
|
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoClientOptions;
|
||||||
|
import com.mongodb.MongoClientOptions.Builder;
|
||||||
|
import com.mongodb.MongoClientURI;
|
||||||
|
import com.mongodb.ServerAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link AbstractMongoConfiguration} that uses {@link MongoClientURI} even when
|
||||||
|
* port is configured for NON {@link Cloud} use cases.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(MongoProperties.class)
|
||||||
|
@ConditionalOnClass(Mongo.class)
|
||||||
|
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
|
||||||
|
@Profile({ "!cloud" })
|
||||||
|
public class MongoConfiguration extends AbstractMongoConfiguration {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(MongoConfiguration.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MongoProperties properties;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private MongoClientOptions options;
|
||||||
|
|
||||||
|
private Mongo mongo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDatabaseName() {
|
||||||
|
return properties.getMongoClientDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes mongo client when destroyd.
|
||||||
|
*/
|
||||||
|
@PreDestroy
|
||||||
|
public void close() {
|
||||||
|
if (this.mongo != null) {
|
||||||
|
this.mongo.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public Mongo mongo() throws UnknownHostException {
|
||||||
|
final MongoClientURI uri = new MongoClientURI(properties.getUri(), createBuilderOutOfOptions(options));
|
||||||
|
|
||||||
|
if (properties.getPort() != null) {
|
||||||
|
LOG.debug("Create mongo by properties (host: {}, port: {})", uri.getHosts().get(0), properties.getPort());
|
||||||
|
this.mongo = new MongoClient(Arrays.asList(new ServerAddress(uri.getHosts().get(0), properties.getPort())),
|
||||||
|
uri.getOptions());
|
||||||
|
} else {
|
||||||
|
LOG.debug("Create mongo by URI : {}", uri);
|
||||||
|
this.mongo = new MongoClient(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mongo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates {@link MongoClientOptions} builder out of existing options as the
|
||||||
|
* {@link MongoClientURI} expects a builder.
|
||||||
|
*
|
||||||
|
* Based on MongoProperties#builder method.
|
||||||
|
*/
|
||||||
|
private Builder createBuilderOutOfOptions(final MongoClientOptions options) {
|
||||||
|
final Builder builder = MongoClientOptions.builder();
|
||||||
|
if (options != null) {
|
||||||
|
builder.alwaysUseMBeans(options.isAlwaysUseMBeans());
|
||||||
|
builder.connectionsPerHost(options.getConnectionsPerHost());
|
||||||
|
builder.connectTimeout(options.getConnectTimeout());
|
||||||
|
builder.cursorFinalizerEnabled(options.isCursorFinalizerEnabled());
|
||||||
|
builder.dbDecoderFactory(options.getDbDecoderFactory());
|
||||||
|
builder.dbEncoderFactory(options.getDbEncoderFactory());
|
||||||
|
builder.description(options.getDescription());
|
||||||
|
builder.maxWaitTime(options.getMaxWaitTime());
|
||||||
|
builder.readPreference(options.getReadPreference());
|
||||||
|
builder.serverSelectionTimeout(options.getServerSelectionTimeout());
|
||||||
|
builder.socketFactory(options.getSocketFactory());
|
||||||
|
builder.socketKeepAlive(options.isSocketKeepAlive());
|
||||||
|
builder.socketTimeout(options.getSocketTimeout());
|
||||||
|
builder.threadsAllowedToBlockForConnectionMultiplier(options
|
||||||
|
.getThreadsAllowedToBlockForConnectionMultiplier());
|
||||||
|
builder.writeConcern(options.getWriteConcern());
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Auto Configure
|
||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
org.eclipse.hawkbit.artifact.repository.ArtifactStoreAutoConfiguration
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FreePortFileWriter {
|
||||||
|
|
||||||
|
private final String filePortPath;
|
||||||
|
private final int from;
|
||||||
|
private final int to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param from
|
||||||
|
* @param to
|
||||||
|
*/
|
||||||
|
public FreePortFileWriter(final int from, final int to, final String filePortPath) {
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.filePortPath = filePortPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return findFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int findFree() {
|
||||||
|
for (int i = from; i <= to; i++) {
|
||||||
|
if (isFree(i)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("No free port in range " + from + ":" + to);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFree(final int port) {
|
||||||
|
try {
|
||||||
|
final File portFile = new File(filePortPath + File.separator + port + ".port");
|
||||||
|
portFile.getParentFile().mkdirs();
|
||||||
|
if (portFile.exists()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
boolean isFree = false;
|
||||||
|
final ServerSocket sock = new ServerSocket();
|
||||||
|
sock.setReuseAddress(true);
|
||||||
|
sock.bind(new InetSocketAddress(port));
|
||||||
|
if (portFile.createNewFile()) {
|
||||||
|
portFile.deleteOnExit();
|
||||||
|
isFree = true;
|
||||||
|
}
|
||||||
|
sock.close();
|
||||||
|
// is free:
|
||||||
|
return isFree;
|
||||||
|
// We rely on an exception thrown to determine availability or
|
||||||
|
// not availability.
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
// not free.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.artifact;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.rules.TestRule;
|
||||||
|
import org.junit.runner.Description;
|
||||||
|
import org.junit.runners.model.Statement;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import de.flapdoodle.embed.mongo.Command;
|
||||||
|
import de.flapdoodle.embed.mongo.MongodExecutable;
|
||||||
|
import de.flapdoodle.embed.mongo.MongodProcess;
|
||||||
|
import de.flapdoodle.embed.mongo.MongodStarter;
|
||||||
|
import de.flapdoodle.embed.mongo.config.ArtifactStoreBuilder;
|
||||||
|
import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder;
|
||||||
|
import de.flapdoodle.embed.mongo.config.IMongodConfig;
|
||||||
|
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
|
||||||
|
import de.flapdoodle.embed.mongo.config.Net;
|
||||||
|
import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder;
|
||||||
|
import de.flapdoodle.embed.mongo.distribution.Version;
|
||||||
|
import de.flapdoodle.embed.process.config.store.HttpProxyFactory;
|
||||||
|
import de.flapdoodle.embed.process.runtime.Network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MongoDBTestRule implements TestRule {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(MongoDBTestRule.class);
|
||||||
|
private static volatile MongodExecutable mongodExecutable = null;
|
||||||
|
private static volatile MongodProcess mongod;
|
||||||
|
private final String id = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Statement apply(final Statement base, final Description description) {
|
||||||
|
return statement(base, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Statement statement(final Statement base, final Description description) {
|
||||||
|
return new Statement() {
|
||||||
|
@Override
|
||||||
|
public void evaluate() throws Throwable {
|
||||||
|
before(base, description);
|
||||||
|
try {
|
||||||
|
base.evaluate();
|
||||||
|
} finally {
|
||||||
|
after();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void after() {
|
||||||
|
if (mongodExecutable != null) {
|
||||||
|
LOG.info("Stop MongoDB...");
|
||||||
|
mongodExecutable.stop();
|
||||||
|
mongodExecutable = null;
|
||||||
|
if (mongod != null) {
|
||||||
|
mongod.stop();
|
||||||
|
mongod = null;
|
||||||
|
}
|
||||||
|
LOG.info("MongoDB stopped... {}", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void before(final Statement base, final Description description) throws UnknownHostException, IOException {
|
||||||
|
final Command command = Command.MongoD;
|
||||||
|
|
||||||
|
final RuntimeConfigBuilder runtimeConfig = new RuntimeConfigBuilder().defaults(command);
|
||||||
|
|
||||||
|
int port = -1;
|
||||||
|
if (System.getProperty("spring.data.mongodb.port") != null) {
|
||||||
|
port = Integer.parseInt(System.getProperty("spring.data.mongodb.port"));
|
||||||
|
} else {
|
||||||
|
port = new FreePortFileWriter(27017, 27100, "./target/freeports").getPort();
|
||||||
|
System.setProperty("spring.data.mongodb.port", String.valueOf(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
Version version = Version.V3_1_0;
|
||||||
|
if (System.getProperty("inf.mongodb.version") != null) {
|
||||||
|
version = Version.valueOf("V" + System.getProperty("inf.mongodb.version").trim().replaceAll("\\.", "_"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.getProperty("http.proxyHost") != null) {
|
||||||
|
runtimeConfig.artifactStore(new ArtifactStoreBuilder().defaults(command)
|
||||||
|
.download(new DownloadConfigBuilder().defaultsForCommand(command)
|
||||||
|
.proxyFactory(new HttpProxyFactory(System.getProperty("http.proxyHost").trim(),
|
||||||
|
Integer.valueOf(System.getProperty("http.proxyPort"))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
final IMongodConfig mongodConfig = new MongodConfigBuilder().version(version)
|
||||||
|
.net(new Net("127.0.0.1", port, Network.localhostIsIPv6())).build();
|
||||||
|
|
||||||
|
final MongodStarter starter = MongodStarter.getInstance(runtimeConfig.build());
|
||||||
|
mongodExecutable = starter.prepare(mongodConfig);
|
||||||
|
LOG.info("Start MongoDB...");
|
||||||
|
mongod = mongodExecutable.start();
|
||||||
|
|
||||||
|
final Net net = mongod.getConfig().net();
|
||||||
|
LOG.info("MongoDB started id {} on bind ip :{} Port:{} and version {}", id, net.getBindIp(), net.getPort(),
|
||||||
|
mongodConfig.version().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
|
||||||
|
@ComponentScan
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
public class TestConfiguration {
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact.repository;
|
||||||
|
|
||||||
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.DigestInputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.eclipse.hawkbit.artifact.MongoDBTestRule;
|
||||||
|
import org.eclipse.hawkbit.artifact.TestConfiguration;
|
||||||
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.data.mongodb.gridfs.GridFsOperations;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import com.mongodb.gridfs.GridFSDBFile;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SpringApplicationConfiguration(classes = { ArtifactStoreAutoConfiguration.class, TestConfiguration.class })
|
||||||
|
public class ArtifactStoreTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final MongoDBTestRule mongoDBRule = new MongoDBTestRule();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ArtifactStore artifactStoreUnderTest;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GridFsOperations gridFs;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void storeArtifactInMongoDB() {
|
||||||
|
final int filelengthBytes = 128;
|
||||||
|
final String filename = "testfile.json";
|
||||||
|
final String contentType = "application/json";
|
||||||
|
final DbArtifact storedFile = artifactStoreUnderTest.store(generateInputStream(filelengthBytes), filename,
|
||||||
|
contentType);
|
||||||
|
|
||||||
|
assertThat(storedFile).isNotNull();
|
||||||
|
assertThat(artifactStoreUnderTest.getArtifactById(storedFile.getArtifactId())).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findArtifactBySHA1Hash() throws NoSuchAlgorithmException {
|
||||||
|
final int filelengthBytes = 128;
|
||||||
|
final String filename = "testfile.json";
|
||||||
|
final String contentType = "application/json";
|
||||||
|
|
||||||
|
final DigestInputStream digestInputStream = digestInputStream(generateInputStream(filelengthBytes), "SHA-1");
|
||||||
|
artifactStoreUnderTest.store(digestInputStream, filename, contentType);
|
||||||
|
assertThat(artifactStoreUnderTest.getArtifactBySha1(
|
||||||
|
BaseEncoding.base16().lowerCase().encode(digestInputStream.getMessageDigest().digest()))).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findArtifactByMD5Hash() throws NoSuchAlgorithmException {
|
||||||
|
final int filelengthBytes = 128;
|
||||||
|
final String filename = "testfile.json";
|
||||||
|
final String contentType = "application/json";
|
||||||
|
|
||||||
|
final DigestInputStream digestInputStream = digestInputStream(generateInputStream(filelengthBytes), "MD5");
|
||||||
|
artifactStoreUnderTest.store(digestInputStream, filename, contentType);
|
||||||
|
assertThat(artifactStoreUnderTest.getArtifactByMd5(
|
||||||
|
BaseEncoding.base16().lowerCase().encode(digestInputStream.getMessageDigest().digest()))).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getInputStreamFromArtifact() throws IOException {
|
||||||
|
final int filelengthBytes = 128;
|
||||||
|
final String filename = "testfile.json";
|
||||||
|
final String contentType = "application/json";
|
||||||
|
|
||||||
|
final ByteArrayInputStream inputStream = generateInputStream(filelengthBytes);
|
||||||
|
final DbArtifact artifact = artifactStoreUnderTest
|
||||||
|
.getArtifactById(artifactStoreUnderTest.store(inputStream, filename, contentType).getArtifactId());
|
||||||
|
inputStream.reset();
|
||||||
|
|
||||||
|
final byte[] artifactBytes = new byte[filelengthBytes];
|
||||||
|
final byte[] artifactStoredBytes = new byte[filelengthBytes];
|
||||||
|
IOUtils.readFully(inputStream, artifactBytes);
|
||||||
|
IOUtils.readFully(artifact.getFileInputStream(), artifactStoredBytes);
|
||||||
|
|
||||||
|
assertThat(artifactBytes).isEqualTo(artifactStoredBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteArtifactWithOnlyOneTenantLast() throws NoSuchAlgorithmException {
|
||||||
|
final int filelengthBytes = 128;
|
||||||
|
final String filename = "testfile.json";
|
||||||
|
final String contentType = "application/json";
|
||||||
|
|
||||||
|
final DigestInputStream digestInputStream = digestInputStream(generateInputStream(filelengthBytes), "SHA-1");
|
||||||
|
final DbArtifact store = artifactStoreUnderTest.store(digestInputStream, filename, contentType);
|
||||||
|
|
||||||
|
artifactStoreUnderTest.deleteById(store.getArtifactId());
|
||||||
|
|
||||||
|
final GridFSDBFile findOne = gridFs
|
||||||
|
.findOne(new Query().addCriteria(Criteria.where("_id").is(store.getArtifactId())));
|
||||||
|
assertThat(findOne).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteArrayInputStream generateInputStream(final int length) {
|
||||||
|
final byte[] bytes = new byte[length];
|
||||||
|
new Random().nextBytes(bytes);
|
||||||
|
return new ByteArrayInputStream(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DigestInputStream digestInputStream(final ByteArrayInputStream stream, final String digest)
|
||||||
|
throws NoSuchAlgorithmException {
|
||||||
|
return new DigestInputStream(stream, MessageDigest.getInstance(digest));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
81
hawkbit-autoconfigure/pom.xml
Executable file
81
hawkbit-autoconfigure/pom.xml
Executable file
@@ -0,0 +1,81 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
|
||||||
|
All rights reserved. This program and the accompanying materials
|
||||||
|
are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
which accompanies this distribution, and is available at
|
||||||
|
http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-parent</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>hawkbit-autoconfigure</artifactId>
|
||||||
|
<name>hawkBit :: Spring Boot Autoconfigure</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-cache-redis</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-dmf-amqp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-ui</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-repository</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-http-security</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-security-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-rest-resource</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context-support</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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.amqp;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.amqp.AmqpConfiguration;
|
||||||
|
import org.eclipse.hawkbit.amqp.annotation.EnableAmqp;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amqp autoconfiguration.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(value = AmqpConfiguration.class)
|
||||||
|
@EnableAmqp
|
||||||
|
public class AmqpAutoConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
197
hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java
vendored
Executable file
197
hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/CacheAutoConfiguration.java
vendored
Executable file
@@ -0,0 +1,197 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.cache.TenancyCacheManager;
|
||||||
|
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
|
||||||
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.cache.guava.GuavaCacheManager;
|
||||||
|
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
|
||||||
|
import org.springframework.cache.interceptor.SimpleCacheResolver;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration for configuring the spring {@link CacheManager} for specific
|
||||||
|
* multi-tenancy caching. The caches between tenants must not interfere each
|
||||||
|
* other.
|
||||||
|
*
|
||||||
|
* This is done by providing a special {@link TenantCacheResolver} which
|
||||||
|
* generates a cache name included the current tenant.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
|
public class CacheAutoConfiguration extends CachingConfigurerSupport {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the default cache manager bean if none other cache manager is
|
||||||
|
* existing.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public TenancyCacheManager cacheManager() {
|
||||||
|
return new TenantAwareCacheManager(new GuavaCacheManager(), tenantAware);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SimpleCacheResolver} implementation which includes the
|
||||||
|
* {@link TenantAware#getCurrentTenant()} into the cache name before
|
||||||
|
* resolving it.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TenantCacheResolver extends SimpleCacheResolver {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.cache.interceptor.AbstractCacheResolver#
|
||||||
|
* resolveCaches(org.springframework
|
||||||
|
* .cache.interceptor.CacheOperationInvocationContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<Cache> resolveCaches(final CacheOperationInvocationContext<?> context) {
|
||||||
|
return super.resolveCaches(context).stream().map(cache -> new TenantCacheWrapper(cache))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.cache.interceptor.SimpleCacheResolver#
|
||||||
|
* getCacheNames(org.springframework
|
||||||
|
* .cache.interceptor.CacheOperationInvocationContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Collection<String> getCacheNames(final CacheOperationInvocationContext<?> context) {
|
||||||
|
return super.getCacheNames(context).stream()
|
||||||
|
.map(cacheName -> tenantAware.getCurrentTenant() + "." + cacheName).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link Cache} wrapper which returns the name of the cache include the
|
||||||
|
* {@link TenantAware#getCurrentTenant()}.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TenantCacheWrapper implements Cache {
|
||||||
|
private final Cache delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param delegate
|
||||||
|
*/
|
||||||
|
public TenantCacheWrapper(final Cache delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* @see org.springframework.cache.Cache#getName()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return tenantAware.getCurrentTenant() + "." + delegate.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* @see org.springframework.cache.Cache#getNativeCache()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object getNativeCache() {
|
||||||
|
return delegate.getNativeCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
* @see org.springframework.cache.Cache#get(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ValueWrapper get(final Object key) {
|
||||||
|
return delegate.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
* @see org.springframework.cache.Cache#get(java.lang.Object,
|
||||||
|
* java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T get(final Object key, final Class<T> type) {
|
||||||
|
return delegate.get(key, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @see org.springframework.cache.Cache#put(java.lang.Object,
|
||||||
|
* java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void put(final Object key, final Object value) {
|
||||||
|
delegate.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
* @see org.springframework.cache.Cache#putIfAbsent(java.lang.Object,
|
||||||
|
* java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ValueWrapper putIfAbsent(final Object key, final Object value) {
|
||||||
|
return delegate.putIfAbsent(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* @see org.springframework.cache.Cache#evict(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void evict(final Object key) {
|
||||||
|
delegate.evict(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @see org.springframework.cache.Cache#clear()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
delegate.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.autoconfigure.cache;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.cache.CacheConstants;
|
||||||
|
import org.eclipse.hawkbit.cache.TenancyCacheManager;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration for configuring a cache for the download id's.
|
||||||
|
*
|
||||||
|
* This is done by providing a named cache.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class DownloadIdCacheAutoConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bean for the downlod id cache.
|
||||||
|
*
|
||||||
|
* @return the cache
|
||||||
|
*/
|
||||||
|
@Bean(name = CacheConstants.DOWNLOAD_ID_CACHE)
|
||||||
|
public Cache downloadIdCache() {
|
||||||
|
if (cacheManager instanceof TenancyCacheManager) {
|
||||||
|
return ((TenancyCacheManager) cacheManager).getDirectCache(CacheConstants.DOWNLOAD_ID_CACHE);
|
||||||
|
}
|
||||||
|
return cacheManager.getCache(CacheConstants.DOWNLOAD_ID_CACHE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/RedisAutoConfiguration.java
vendored
Executable file
27
hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/cache/RedisAutoConfiguration.java
vendored
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.cache.RedisConfiguration;
|
||||||
|
import org.eclipse.hawkbit.cache.annotation.EnableRedis;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration for configuring the redis configuration.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(value = RedisConfiguration.class)
|
||||||
|
@EnableRedis
|
||||||
|
public class RedisAutoConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.autoconfigure.conf;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconfiguration which loads the default configuration properties for
|
||||||
|
* hawkbit.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@PropertySource("classpath:/hawkbitdefaults.properties")
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
public class DefaultPropertiesAutoConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.autoconfigure.eventbus;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.eventbus.EventBusSubscriberProcessor;
|
||||||
|
import org.eclipse.hawkbit.eventbus.EventSubscriber;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AsyncEventBus;
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class EventBusAutoConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("asyncExecutor")
|
||||||
|
private Executor executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server internal eventBus that allows parallel event processing if the
|
||||||
|
* subscriber is marked as so.
|
||||||
|
*
|
||||||
|
* @return eventbus bean
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public EventBus eventBus() {
|
||||||
|
return new AsyncEventBus(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link EventBusSubscriberProcessor} to find classes annotated
|
||||||
|
* with {@link EventSubscriber}.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public EventBusSubscriberProcessor eventBusSubscriberProcessor() {
|
||||||
|
return new EventBusSubscriberProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.autoconfigure.scheduling;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||||
|
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAsync
|
||||||
|
@ConditionalOnMissingBean(AsyncConfigurer.class)
|
||||||
|
public class AsyncConfigurerAutoConfiguration implements AsyncConfigurer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("asyncExecutor")
|
||||||
|
private Executor executor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Executor getAsyncExecutor() {
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||||
|
return new SimpleAsyncUncaughtExceptionHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 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.scheduling;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for the async configurer.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("hawkbit.threadpool")
|
||||||
|
public class AsyncConfigurerThreadpoolProperties {
|
||||||
|
|
||||||
|
private Integer queuesize = 250;
|
||||||
|
|
||||||
|
private Integer corethreads = 5;
|
||||||
|
|
||||||
|
private Integer maxthreads = 50;
|
||||||
|
|
||||||
|
private Long idletimeout = 10000L;
|
||||||
|
|
||||||
|
public Integer getQueuesize() {
|
||||||
|
return queuesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQueuesize(final Integer queuesize) {
|
||||||
|
this.queuesize = queuesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCorethreads() {
|
||||||
|
return corethreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorethreads(final Integer corethreads) {
|
||||||
|
this.corethreads = corethreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxthreads() {
|
||||||
|
return maxthreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxthreads(final Integer maxthreads) {
|
||||||
|
this.maxthreads = maxthreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getIdletimeout() {
|
||||||
|
return idletimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdletimeout(final Long idletimeout) {
|
||||||
|
this.idletimeout = idletimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.autoconfigure.scheduling;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.concurrent.DelegatingSecurityContextExecutor;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(AsyncConfigurerThreadpoolProperties.class)
|
||||||
|
public class ExecutorAutoConfiguration {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ExecutorAutoConfiguration.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ExecutorService for general pupose multi threaded operations
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public Executor asyncExecutor() {
|
||||||
|
final BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(
|
||||||
|
asyncConfigurerProperties.getQueuesize());
|
||||||
|
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
|
||||||
|
asyncConfigurerProperties.getCorethreads(), asyncConfigurerProperties.getMaxthreads(),
|
||||||
|
asyncConfigurerProperties.getIdletimeout(), TimeUnit.MILLISECONDS, blockingQueue,
|
||||||
|
new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build());
|
||||||
|
threadPoolExecutor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
|
||||||
|
@Override
|
||||||
|
public void rejectedExecution(final Runnable r, final java.util.concurrent.ThreadPoolExecutor executor) {
|
||||||
|
LOGGER.warn("Reject runnable for centralExecutorService, reached limit of queue size {}", executor
|
||||||
|
.getQueue().size());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new DelegatingSecurityContextExecutor(threadPoolExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the executor for UI background processes.
|
||||||
|
*/
|
||||||
|
@Bean(name = "uiExecutor")
|
||||||
|
@ConditionalOnMissingBean(name = "uiExecutor")
|
||||||
|
public Executor uiExecutor() {
|
||||||
|
final BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(20);
|
||||||
|
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 20, 10000, TimeUnit.MILLISECONDS,
|
||||||
|
blockingQueue, new ThreadFactoryBuilder().setNameFormat("ui-executor-pool-%d").build());
|
||||||
|
threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
return new DelegatingSecurityContextExecutor(threadPoolExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.autoconfigure.security;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation to enable the managed security configuration.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Import(SecurityManagedConfiguration.class)
|
||||||
|
public @interface EnableHawkbitManagedSecurityConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
/**
|
||||||
|
* 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.security;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator;
|
||||||
|
import org.eclipse.hawkbit.im.authentication.PermissionService;
|
||||||
|
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.SpringSecurityAuditorAware;
|
||||||
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.domain.AuditorAware;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} for security.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(SecurityProperties.class)
|
||||||
|
public class SecurityAutoConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link TenantAware} singleton bean which holds the current
|
||||||
|
* {@link TenantAware} service and make it accessible in beans which
|
||||||
|
* cannot access the service directly, e.g. JPA entities.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public TenantAware tenantAware() {
|
||||||
|
return new SecurityContextTenantAware();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return permission service to check if current user has the necessary
|
||||||
|
* permissions.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public PermissionService permissionService() {
|
||||||
|
return new PermissionService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the auditore aware.
|
||||||
|
*
|
||||||
|
* @return the spring security auditore aware
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public AuditorAware<String> auditorAware() {
|
||||||
|
return new SpringSecurityAuditorAware();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-configuration for the in-memory-user-management.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnMissingBean(value = { UserAuthenticationFilter.class })
|
||||||
|
public static class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryUserManagementConfiguration.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationConfiguration configuration;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.security.config.annotation.authentication.
|
||||||
|
* configurers. GlobalAuthenticationConfigurerAdapter
|
||||||
|
* #configure(org.springframework.security.config.annotation.
|
||||||
|
* authentication.builders.AuthenticationManagerBuilder)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider();
|
||||||
|
userDaoAuthenticationProvider.setUserDetailsService(userDetailsService());
|
||||||
|
auth.authenticationProvider(userDaoAuthenticationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the user details service to load a user from memory user
|
||||||
|
* manager.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public UserDetailsService userDetailsService() {
|
||||||
|
final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(
|
||||||
|
new ArrayList<>());
|
||||||
|
inMemoryUserDetailsManager.setAuthenticationManager(null);
|
||||||
|
inMemoryUserDetailsManager.createUser(new User("admin", "admin", getAllAuthorities()));
|
||||||
|
return inMemoryUserDetailsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the multi-tenancy indicator to disallow multi-tenancy
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MultitenancyIndicator multiTenancyIndicator() {
|
||||||
|
return new MultitenancyIndicator() {
|
||||||
|
@Override
|
||||||
|
public boolean isMultiTenancySupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<SimpleGrantedAuthority> getAllAuthorities() {
|
||||||
|
final List<SimpleGrantedAuthority> allPermissions = new ArrayList<>();
|
||||||
|
final Field[] declaredFields = SpPermission.class.getDeclaredFields();
|
||||||
|
for (final Field field : declaredFields) {
|
||||||
|
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
try {
|
||||||
|
final String permissionName = (String) field.get(null);
|
||||||
|
allPermissions.add(new SimpleGrantedAuthority(permissionName));
|
||||||
|
} catch (final IllegalAccessException e) {
|
||||||
|
LOGGER.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider {
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.security.authentication.dao.
|
||||||
|
* AbstractUserDetailsAuthenticationProvider
|
||||||
|
* #createSuccessAuthentication(java.lang.Object,
|
||||||
|
* org.springframework.security.core.Authentication,
|
||||||
|
* org.springframework.security.core.userdetails.UserDetails)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Authentication createSuccessAuthentication(final Object principal,
|
||||||
|
final Authentication authentication, final UserDetails user) {
|
||||||
|
final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
|
||||||
|
authentication.getCredentials(), user.getAuthorities());
|
||||||
|
result.setDetails(new TenantAwareAuthenticationDetails("DEFAULT", false));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link UserAuthenticationFilter} to include into the SP
|
||||||
|
* security configuration.
|
||||||
|
* @throws Exception
|
||||||
|
* lazy bean exception maybe if the authentication manager
|
||||||
|
* cannot be instantiated
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public UserAuthenticationFilter userAuthenticationFilter() throws Exception {
|
||||||
|
return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class UserAuthenticationFilterBasicAuth extends BasicAuthenticationFilter
|
||||||
|
implements UserAuthenticationFilter {
|
||||||
|
|
||||||
|
private UserAuthenticationFilterBasicAuth(final AuthenticationManager authenticationManager) {
|
||||||
|
super(authenticationManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,563 @@
|
|||||||
|
/**
|
||||||
|
* 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.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter;
|
||||||
|
import org.eclipse.hawkbit.cache.CacheConstants;
|
||||||
|
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||||
|
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||||
|
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
|
||||||
|
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
||||||
|
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||||
|
import org.eclipse.hawkbit.rest.resource.RestConstants;
|
||||||
|
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
|
||||||
|
import org.eclipse.hawkbit.security.DosFilter;
|
||||||
|
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.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.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;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||||
|
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy;
|
||||||
|
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
|
||||||
|
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
|
||||||
|
import org.vaadin.spring.security.VaadinSecurityContext;
|
||||||
|
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
|
||||||
|
import org.vaadin.spring.security.web.VaadinDefaultRedirectStrategy;
|
||||||
|
import org.vaadin.spring.security.web.VaadinRedirectStrategy;
|
||||||
|
import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
|
||||||
|
import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All configurations related to SP authentication and authorization layer.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
|
||||||
|
@EnableWebMvcSecurity
|
||||||
|
@Order(value = Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
public class SecurityManagedConfiguration implements EnvironmentAware {
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link WebSecurityConfigurer} for the internal SP controller API.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Order(300)
|
||||||
|
static class ControllerSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ControllerManagement controllerManagement;
|
||||||
|
@Autowired
|
||||||
|
private SystemManagement systemManagement;
|
||||||
|
@Autowired
|
||||||
|
private TenantAware tenantAware;
|
||||||
|
@Autowired
|
||||||
|
private SecurityProperties securityConfiguration;
|
||||||
|
@Autowired
|
||||||
|
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
|
||||||
|
|
||||||
|
@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);
|
||||||
|
securityHeaderFilter.setAuthenticationManager(authenticationManager());
|
||||||
|
securityHeaderFilter.setCheckForPrincipalChanges(true);
|
||||||
|
securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||||
|
|
||||||
|
final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
|
||||||
|
systemManagement, tenantAware, controllerManagement);
|
||||||
|
securityTokenFilter.setAuthenticationManager(authenticationManager());
|
||||||
|
securityTokenFilter.setCheckForPrincipalChanges(true);
|
||||||
|
securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||||
|
|
||||||
|
final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
|
||||||
|
systemManagement, tenantAware);
|
||||||
|
gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager());
|
||||||
|
gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
|
||||||
|
gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||||
|
|
||||||
|
HttpSecurity httpSec = http.csrf().disable().headers()
|
||||||
|
.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY)).contentTypeOptions()
|
||||||
|
.xssProtection().httpStrictTransportSecurity().and();
|
||||||
|
|
||||||
|
if (springSecurityProperties.isRequireSsl()) {
|
||||||
|
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (securityConfiguration.getAnonymousEnabled()) {
|
||||||
|
LOG.info(
|
||||||
|
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
|
||||||
|
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
|
||||||
|
"controllerAnonymousFilter", "anonymous", Collections.singletonList(
|
||||||
|
new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
|
||||||
|
anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||||
|
httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and()
|
||||||
|
.securityContext().disable().anonymous().authenticationFilter(anoymousFilter);
|
||||||
|
} else {
|
||||||
|
httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
|
||||||
|
.addFilter(gatewaySecurityTokenFilter).antMatcher("/*/controller/**").anonymous().disable()
|
||||||
|
.authorizeRequests().anyRequest().authenticated().and().exceptionHandling()
|
||||||
|
.authenticationEntryPoint(new AuthenticationEntryPoint() {
|
||||||
|
@Override
|
||||||
|
public void commence(final HttpServletRequest request, final HttpServletResponse response,
|
||||||
|
final AuthenticationException authException) throws IOException, ServletException {
|
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
}
|
||||||
|
}).and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to protect the SP server against denial of service attacks.
|
||||||
|
*
|
||||||
|
* @return he spring filter registration bean for registering an denial of
|
||||||
|
* service protection filter in the filter chain
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@Order(50)
|
||||||
|
public FilterRegistrationBean dosFilter() {
|
||||||
|
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
|
||||||
|
|
||||||
|
filterRegBean
|
||||||
|
.setFilter(
|
||||||
|
new DosFilter(environment.getProperty("security.dos.filter.maxRead", Integer.class, 100),
|
||||||
|
environment.getProperty("security.dos.filter.maxWrite", Integer.class, 10),
|
||||||
|
environment.getProperty("security.dos.filter.whitelist"), environment
|
||||||
|
.getProperty("security.clients.blacklist"),
|
||||||
|
environment.getProperty("security.rp.remote_ip_header", String.class, "X-Forwarded-For")));
|
||||||
|
filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*");
|
||||||
|
return filterRegBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter registration bean for spring etag filter.
|
||||||
|
*
|
||||||
|
* @return the spring filter registration bean for registering an etag
|
||||||
|
* filter in the filter chain
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@Order(100)
|
||||||
|
public FilterRegistrationBean eTagFilter() {
|
||||||
|
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
|
||||||
|
// eclude the URLs for downloading artifacts, so no eTag is generated in
|
||||||
|
// the
|
||||||
|
// ShallowEtagHeaderFilter, just using the SH1 hash of the artifact
|
||||||
|
// itself as 'ETag', because
|
||||||
|
// otherwise the file will be copied in memory!
|
||||||
|
filterRegBean.setFilter(new ExcludePathAwareShallowETagFilter(
|
||||||
|
"/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/{tenant}/controller/artifacts/**",
|
||||||
|
"/{targetid}/softwaremodules/{softwareModuleId}/artifacts/**"));
|
||||||
|
return filterRegBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security configuration for the REST management API of the health url.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Order(310)
|
||||||
|
public static class HealthSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(final HttpSecurity http) throws Exception {
|
||||||
|
http.regexMatcher("/system/health").csrf().disable().httpBasic().and().sessionManagement()
|
||||||
|
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security configuration for the REST management API.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Order(350)
|
||||||
|
public static class RestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||||
|
@Autowired
|
||||||
|
private UserAuthenticationFilter userAuthenticationFilter;
|
||||||
|
@Autowired
|
||||||
|
private SystemManagement systemManagement;
|
||||||
|
@Autowired
|
||||||
|
private TenantAware tenantAware;
|
||||||
|
@Autowired
|
||||||
|
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(final HttpSecurity http) throws Exception {
|
||||||
|
|
||||||
|
HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system.*").csrf().disable();
|
||||||
|
if (springSecurityProperties.isRequireSsl()) {
|
||||||
|
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
|
||||||
|
}
|
||||||
|
httpSec.addFilterBefore(new Filter() {
|
||||||
|
@Override
|
||||||
|
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||||
|
userAuthenticationFilter.init(filterConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(final ServletRequest request, final ServletResponse response,
|
||||||
|
final FilterChain chain) throws IOException, ServletException {
|
||||||
|
userAuthenticationFilter.doFilter(request, response, chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
userAuthenticationFilter.destroy();
|
||||||
|
}
|
||||||
|
}, RequestHeaderAuthenticationFilter.class)
|
||||||
|
.addFilterAfter(
|
||||||
|
new AuthenticationSuccessTenantMetadataCreationFilter(tenantAware, systemManagement),
|
||||||
|
RequestHeaderAuthenticationFilter.class)
|
||||||
|
.authorizeRequests().anyRequest().authenticated()
|
||||||
|
.antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
|
||||||
|
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN).antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/**")
|
||||||
|
.hasAnyAuthority(SpPermission.SYSTEM_DIAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link WebSecurityConfigurer} for external (management) access.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Order(400)
|
||||||
|
@EnableVaadinSecurity
|
||||||
|
public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter
|
||||||
|
implements EnvironmentAware {
|
||||||
|
|
||||||
|
private static final String XFRAME_OPTION_DENY = "DENY";
|
||||||
|
private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN";
|
||||||
|
private static final String XFAME_OPTION_ALLOW_FROM = "ALLOW-FROM";
|
||||||
|
@Autowired
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* post construct for setting the authentication success handler for the
|
||||||
|
* vaadin security context.
|
||||||
|
*/
|
||||||
|
@PostConstruct
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
this.vaadinSecurityContext.addAuthenticationSuccessHandler(redirectSaveHandler());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "authenticationManager")
|
||||||
|
@Override
|
||||||
|
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||||
|
return super.authenticationManagerBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The VaadinRedirectStategy
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public VaadinRedirectStrategy vaadinRedirectStrategy() {
|
||||||
|
return new VaadinDefaultRedirectStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the vaadin success authentication handler
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public VaadinAuthenticationSuccessHandler redirectSaveHandler() {
|
||||||
|
final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler();
|
||||||
|
handler.setRedirectStrategy(vaadinRedirectStrategy());
|
||||||
|
handler.setDefaultTargetUrl("/UI/");
|
||||||
|
handler.setTargetUrlParameter("r");
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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) {
|
||||||
|
// 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, "
|
||||||
|
+ "please ensure to set allow from URIs");
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround regex: we need to exclude the URL /UI/HEARTBEAT here
|
||||||
|
// because we bound the
|
||||||
|
// vaadin application to /UI and not to root, described in
|
||||||
|
// vaadin-forum:
|
||||||
|
// https://vaadin.com/forum#!/thread/3200565.
|
||||||
|
HttpSecurity httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/UI.*$")
|
||||||
|
// disable as CSRF is handled by Vaadin
|
||||||
|
.csrf().disable();
|
||||||
|
|
||||||
|
if (springSecurityProperties.isRequireSsl()) {
|
||||||
|
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
|
||||||
|
} else {
|
||||||
|
LOG.info(
|
||||||
|
"\"******************\\n** Requires HTTPS Security has been disabled for UI, should only use for developing purposes **\\n******************\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
// for UI integrator we allow frame integration on same origin
|
||||||
|
httpSec.headers()
|
||||||
|
.addHeaderWriter(confXframeOption.equals(XFAME_OPTION_ALLOW_FROM)
|
||||||
|
? new XFrameOptionsHeaderWriter(new StaticAllowFromStrategy(new URI(confAllowFromUri)))
|
||||||
|
: new XFrameOptionsHeaderWriter(xframeOptionFromStr(confXframeOption)))
|
||||||
|
.contentTypeOptions().xssProtection().httpStrictTransportSecurity().and()
|
||||||
|
// UI
|
||||||
|
.authorizeRequests().antMatchers("/UI/login/**").permitAll().antMatchers("/UI/UIDL/**").permitAll()
|
||||||
|
.anyRequest().authenticated().and()
|
||||||
|
// UI login / logout
|
||||||
|
.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login/#/"))
|
||||||
|
.and().logout().logoutUrl("/UI/logout").logoutSuccessUrl("/UI/login/#/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a given string into the {@link XFrameOptionsMode} enum. Only
|
||||||
|
* {@link XFrameOptionsMode#DENY} and
|
||||||
|
* {@link XFrameOptionsMode#SAMEORIGIN} any other string will be
|
||||||
|
* converted to the default {@link XFrameOptionsMode#SAMEORIGIN}.
|
||||||
|
*
|
||||||
|
* @param xframeOption
|
||||||
|
* the string of the xframe option
|
||||||
|
* @return an {@link XFrameOptionsMode} by the given string, in case
|
||||||
|
* string does not match an option then
|
||||||
|
* {@link XFrameOptionsMode#SAMEORIGIN} is returned
|
||||||
|
*/
|
||||||
|
private XFrameOptionsMode xframeOptionFromStr(@NotNull final String xframeOption) {
|
||||||
|
switch (xframeOption) {
|
||||||
|
case XFRAME_OPTION_DENY:
|
||||||
|
return XFrameOptionsMode.DENY;
|
||||||
|
case XFRAME_OPTION_SAMEORIGIN:
|
||||||
|
// fall through to default because the same
|
||||||
|
default:
|
||||||
|
return XFrameOptionsMode.SAMEORIGIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(final WebSecurity webSecurity) throws Exception {
|
||||||
|
webSecurity.ignoring().antMatchers("/documentation/**", "/VAADIN/**", "/*.*", "/v2/api-docs/**",
|
||||||
|
"/docs/**");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Websecruity config to handle and filter the download ids.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@Order(200)
|
||||||
|
public static class IdRestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SecurityProperties securityConfiguration;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
|
||||||
|
private Cache downloadIdCache;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(final HttpSecurity http) throws Exception {
|
||||||
|
final HttpDownloadAuthenticationFilter downloadIdAuthenticationFilter = new HttpDownloadAuthenticationFilter(
|
||||||
|
downloadIdCache);
|
||||||
|
downloadIdAuthenticationFilter.setAuthenticationManager(authenticationManager());
|
||||||
|
|
||||||
|
http.csrf().disable();
|
||||||
|
http.anonymous().disable();
|
||||||
|
|
||||||
|
http.regexMatcher(HttpDownloadAuthenticationFilter.REQUEST_ID_REGEX_PATTERN)
|
||||||
|
.addFilterBefore(downloadIdAuthenticationFilter, FilterSecurityInterceptor.class);
|
||||||
|
http.authorizeRequests().anyRequest().authenticated();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.authenticationProvider(
|
||||||
|
new PreAuthTokenSourceTrustAuthenticationProvider(securityConfiguration.getRpTrustedIPs()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After a successful login on the UI we need to ensure to create the tenant
|
||||||
|
* meta data within SP.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends VaadinUrlAuthenticationSuccessHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SystemManagement systemManagement;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.vaadin.spring.security.web.authentication.
|
||||||
|
* SavedRequestAwareVaadinAuthenticationSuccessHandler
|
||||||
|
* #onAuthenticationSuccess(org.springframework.security.core.
|
||||||
|
* Authentication)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
|
||||||
|
if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
|
||||||
|
systemManagement
|
||||||
|
.getTenantMetadata(((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
|
||||||
|
} else if (authentication.getClass().equals(UsernamePasswordAuthenticationToken.class)) {
|
||||||
|
// TODO: MECS-1078 vaadin4spring-ext-security does not give us the
|
||||||
|
// fullyAuthenticatedToken
|
||||||
|
// in the GenericVaadinSecurity class. Only the token which has been
|
||||||
|
// created in the
|
||||||
|
// LoginView. This needs to be changed with the update of
|
||||||
|
// vaadin4spring 0.0.7 because it
|
||||||
|
// has been fixed.
|
||||||
|
systemManagement.getTenantMetadata("DEFAULT");
|
||||||
|
}
|
||||||
|
super.onAuthenticationSuccess(authentication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sevletfilter to create metadata after successful authentication over RESTful.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
|
||||||
|
|
||||||
|
private final TenantAware tenantAware;
|
||||||
|
private final SystemManagement systemManagement;
|
||||||
|
|
||||||
|
AuthenticationSuccessTenantMetadataCreationFilter(final TenantAware tenantAware,
|
||||||
|
final SystemManagement systemManagement) {
|
||||||
|
this.tenantAware = tenantAware;
|
||||||
|
this.systemManagement = systemManagement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||||
|
// not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
final String currentTenant = tenantAware.getCurrentTenant();
|
||||||
|
if (currentTenant != null) {
|
||||||
|
// lazy initialize tenant meta data after successful authentication
|
||||||
|
systemManagement.getTenantMetadata(currentTenant);
|
||||||
|
}
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// not needed
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* 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.swagger;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.rest.resource.RestConstants;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
|
|
||||||
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
|
import springfox.documentation.builders.PathSelectors;
|
||||||
|
import springfox.documentation.schema.ModelRef;
|
||||||
|
import springfox.documentation.service.ApiInfo;
|
||||||
|
import springfox.documentation.service.ResponseMessage;
|
||||||
|
import springfox.documentation.spi.DocumentationType;
|
||||||
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
|
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swagger configuration for RESTful SP server APIs.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableSwagger2
|
||||||
|
public class SwaggerApiDocAutoConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Springfox Docket, which generates the Information for the
|
||||||
|
* REST-Swagger-UI. Rest paths are: /rest/v1/. and ./controller/v1/.
|
||||||
|
*
|
||||||
|
* @see springfox.documentation.spring.web.plugins.Docket
|
||||||
|
*
|
||||||
|
* @return the v1 docket
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Docket customImplementation() {
|
||||||
|
return createDocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<String> selectApiPaths() {
|
||||||
|
return Predicates.or(PathSelectors.regex("/rest/v1/.*"), PathSelectors.regex("/.*/controller/v1/.*"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Docket createDocket() {
|
||||||
|
final List<ResponseMessage> authorizationMessages = globalAuhtorizationMessages();
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2).select().paths(selectApiPaths()).build()
|
||||||
|
.useDefaultResponseMessages(true).globalResponseMessage(RequestMethod.GET, authorizationMessages)
|
||||||
|
.globalResponseMessage(RequestMethod.POST, authorizationMessages)
|
||||||
|
.globalResponseMessage(RequestMethod.PUT, authorizationMessages)
|
||||||
|
.globalResponseMessage(RequestMethod.DELETE, authorizationMessages).apiInfo(apiInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ResponseMessage> globalAuhtorizationMessages() {
|
||||||
|
final List<ResponseMessage> messageList = new ArrayList<>();
|
||||||
|
messageList.add(new ResponseMessage(200, "Request sucessfull", new ModelRef("com.")));
|
||||||
|
messageList.add(new ResponseMessage(400, "Bad Request - e.g. invalid parameters", null));
|
||||||
|
messageList.add(new ResponseMessage(401, "Unauthorized - The request requires user authentication.",
|
||||||
|
|
||||||
|
null));
|
||||||
|
messageList.add(
|
||||||
|
new ResponseMessage(403, "Forbidden - Insufficient permissions or data volume restriction applies.",
|
||||||
|
new ModelRef("ExceptionInfo")));
|
||||||
|
messageList.add(new ResponseMessage(405, "Method Not Allowed", null));
|
||||||
|
messageList.add(new ResponseMessage(406,
|
||||||
|
"Not Acceptable - In case accept header is specified and not application/json", null));
|
||||||
|
messageList.add(new ResponseMessage(429,
|
||||||
|
"Too many requests. The server will refuse further attemps and the client has to wait another second.",
|
||||||
|
null));
|
||||||
|
return messageList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiInfo apiInfo() {
|
||||||
|
return new ApiInfoBuilder().title("Software Provisioning API Descriptions").version(RestConstants.API_VERSION)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.autoconfigure.ui;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.DistributedResourceBundleMessageSource;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.vaadin.spring.annotation.EnableVaadinExtensions;
|
||||||
|
import org.vaadin.spring.events.annotation.EnableEventBus;
|
||||||
|
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hawkbit-ui autoconfiguration.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableVaadinSecurity
|
||||||
|
@EnableVaadinExtensions
|
||||||
|
@EnableEventBus
|
||||||
|
public class UIAutoConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message source bean to add distributed message sources.
|
||||||
|
*
|
||||||
|
* @return the message bean.
|
||||||
|
*/
|
||||||
|
@Bean(name = "messageSource")
|
||||||
|
public DistributedResourceBundleMessageSource messageSource() {
|
||||||
|
return new DistributedResourceBundleMessageSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* 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 java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.api.HostnameResolver;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconfiguration of the {@link HostnameResolver} based on a property.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(ServerProperties.class)
|
||||||
|
public class PropertyHostnameResolverAutoConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ServerProperties serverProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the default autoconfigure hostname resolver implementation which
|
||||||
|
* is property based specified by the property {@link #url}
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(value = HostnameResolver.class)
|
||||||
|
public HostnameResolver hostnameResolver() {
|
||||||
|
return new HostnameResolver() {
|
||||||
|
@Override
|
||||||
|
public URL resolveHostname() {
|
||||||
|
try {
|
||||||
|
return new URL(serverProperties.getUrl());
|
||||||
|
} catch (final MalformedURLException e) {
|
||||||
|
throw Throwables.propagate(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.autoconfigure.web;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.controller.EnableDirectDeviceApi;
|
||||||
|
import org.eclipse.hawkbit.rest.resource.EnableRestResources;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-Configuration for enabling the REST-Resources.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ EnableDirectDeviceApi.class, EnableRestResources.class })
|
||||||
|
@Import({ EnableDirectDeviceApi.class, EnableRestResources.class })
|
||||||
|
public class ResourceControllerAutoConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* 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.web;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
|
||||||
|
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration bean which disables the {@code useSuffixPatternMatch} feature
|
||||||
|
* from Spring because it will truncate the dot in a REST URL which leads to
|
||||||
|
* problem in case a controllerId contains dots and is a path parameter or
|
||||||
|
* filename ending.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class WebMvcAutoConfiguration extends WebMvcConfigurerAdapter {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
||||||
|
* #configurePathMatch
|
||||||
|
* (org.springframework.web.servlet.config.annotation.PathMatchConfigurer)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configurePathMatch(final PathMatchConfigurer configurer) {
|
||||||
|
configurer.setUseSuffixPatternMatch(false);
|
||||||
|
configurer.setUseRegisteredSuffixPatternMatch(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.web.servlet.config.annotation.
|
||||||
|
* WebMvcConfigurerAdapter# configureContentNegotiation
|
||||||
|
* (org.springframework.web.servlet.config.annotation.
|
||||||
|
* ContentNegotiationConfigurer)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
|
||||||
|
configurer.favorPathExtension(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories
Executable file
16
hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
# Auto Configure
|
||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.conf.DefaultPropertiesAutoConfiguration,\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.ui.UIAutoConfiguration,\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.security.SecurityAutoConfiguration,\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.swagger.SwaggerApiDocAutoConfiguration,\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.url.PropertyHostnameResolverAutoConfiguration,\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.web.WebMvcAutoConfiguration,\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.cache.CacheAutoConfiguration,\
|
||||||
|
org.eclipse.hawkbit.autoconfigure.cache.DownloadIdCacheAutoConfiguration,\
|
||||||
|
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
|
||||||
57
hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties
Executable file
57
hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties
Executable 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
|
||||||
|
#
|
||||||
|
|
||||||
|
# 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
|
||||||
|
spring.jpa.show-sql=false
|
||||||
|
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
|
||||||
|
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.urlMapping=/UI/*
|
||||||
|
vaadin.servlet.params.heartbeatInterval=60
|
||||||
|
vaadin.servlet.params.closeIdleSessions=false
|
||||||
|
|
||||||
|
# Spring MVC
|
||||||
|
spring.mvc.favicon.enabled=false
|
||||||
|
|
||||||
|
|
||||||
|
# Defines the thread pool executor
|
||||||
|
hawkbit.threadpool.corethreads=5
|
||||||
|
hawkbit.threadpool.maxthreads=20
|
||||||
|
hawkbit.threadpool.idletimeout=10000
|
||||||
|
hawkbit.threadpool.queuesize=250
|
||||||
|
|
||||||
|
# Defines the polling time for the controllers in HH:MM:SS notation
|
||||||
|
hawkbit.controller.pollingTime=00:05:00
|
||||||
|
hawkbit.controller.pollingOverdueTime=00:05:00
|
||||||
|
|
||||||
|
## Configuration for RabbitMQ integration
|
||||||
|
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
|
||||||
|
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
|
||||||
|
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
|
||||||
70
hawkbit-cache-redis/pom.xml
Executable file
70
hawkbit-cache-redis/pom.xml
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
|
||||||
|
All rights reserved. This program and the accompanying materials
|
||||||
|
are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
which accompanies this distribution, and is available at
|
||||||
|
http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-parent</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>hawkbit-cache-redis</artifactId>
|
||||||
|
<name>hawkBit :: Redis Cache Manager</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.data</groupId>
|
||||||
|
<artifactId>spring-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>redis.clients</groupId>
|
||||||
|
<artifactId>jedis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.easytesting</groupId>
|
||||||
|
<artifactId>fest-assert-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.easytesting</groupId>
|
||||||
|
<artifactId>fest-assert</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.hateoas</groupId>
|
||||||
|
<artifactId>spring-hateoas</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.yandex.qatools.allure</groupId>
|
||||||
|
<artifactId>allure-junit-adaptor</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
109
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java
vendored
Executable file
109
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java
vendored
Executable file
@@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.cache.eventbus.EventDistributor;
|
||||||
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||||
|
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
|
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||||
|
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)
|
||||||
|
public class RedisConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisProperties redisProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link EventDistributor} to distribute and consume the events
|
||||||
|
* from Redis
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public EventDistributor eventDistributor() {
|
||||||
|
return new EventDistributor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the spring redis cache manager.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public CacheManager cacheManager() {
|
||||||
|
return new TenantAwareCacheManager(new RedisCacheManager(redisTemplate()), tenantAware);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the redis connection factory to create a redis connection based
|
||||||
|
* on the {@link RedisProperties}
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public JedisConnectionFactory jedisConnectionFactory() {
|
||||||
|
final JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||||
|
factory.setHostName(redisProperties.getHost());
|
||||||
|
factory.setPort(redisProperties.getPort());
|
||||||
|
factory.setUsePool(true);
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the spring {@link RedisTemplate} configured with the necessary
|
||||||
|
* object serializers
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public RedisTemplate<String, Object> redisTemplate() {
|
||||||
|
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
|
||||||
|
redisTemplate.setConnectionFactory(jedisConnectionFactory());
|
||||||
|
redisTemplate.setKeySerializer(new JdkSerializationRedisSerializer());
|
||||||
|
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
|
||||||
|
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
|
||||||
|
return redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the spring-redis message listener adapter to consume messages
|
||||||
|
* from the Redis server
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MessageListenerAdapter messageListenerAdapter() {
|
||||||
|
final MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(eventDistributor());
|
||||||
|
messageListenerAdapter.setSerializer(new JdkSerializationRedisSerializer());
|
||||||
|
return messageListenerAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the spring-redis message listener container to register the
|
||||||
|
* message listener adapter
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public RedisMessageListenerContainer redisContainer() {
|
||||||
|
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||||
|
container.setConnectionFactory(jedisConnectionFactory());
|
||||||
|
container.addMessageListener(messageListenerAdapter(), eventDistributor().getTopics());
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
56
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisProperties.java
vendored
Executable file
56
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisProperties.java
vendored
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.cache;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the host
|
||||||
|
*/
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param host
|
||||||
|
* the host to set
|
||||||
|
*/
|
||||||
|
public void setHost(final String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the port
|
||||||
|
*/
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param port
|
||||||
|
* the port to set
|
||||||
|
*/
|
||||||
|
public void setPort(final int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/annotation/EnableRedis.java
vendored
Executable file
29
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/annotation/EnableRedis.java
vendored
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.cache.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.cache.RedisConfiguration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation to enable redis caching.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Import(RedisConfiguration.class)
|
||||||
|
public @interface EnableRedis {
|
||||||
|
|
||||||
|
}
|
||||||
138
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/eventbus/EventDistributor.java
vendored
Executable file
138
hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/eventbus/EventDistributor.java
vendored
Executable file
@@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache.eventbus;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.eventbus.EventSubscriber;
|
||||||
|
import org.eclipse.hawkbit.eventbus.event.DistributedEvent;
|
||||||
|
import org.eclipse.hawkbit.eventbus.event.Event;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.listener.PatternTopic;
|
||||||
|
import org.springframework.data.redis.listener.Topic;
|
||||||
|
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@EventSubscriber
|
||||||
|
public class EventDistributor {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(EventDistributor.class);
|
||||||
|
/**
|
||||||
|
* the node id to filter self published events in the redis message
|
||||||
|
* subscriber.
|
||||||
|
*/
|
||||||
|
private static final String NODE_ID = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
private static final String DISTRIBUTION_CHANNEL_TOPIC = "com/bosch/sp/distEvent";
|
||||||
|
private static final String SEND_DISTRIBUTION_CHANNEL = DISTRIBUTION_CHANNEL_TOPIC + "/" + NODE_ID;
|
||||||
|
private static final String SUB_DISTRIBUTION_CHANNEL = DISTRIBUTION_CHANNEL_TOPIC + "*";
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventBus eventBus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* consumes all {@link DistributedEvent}s posted on the {@link EventBus} and
|
||||||
|
* distribute them to the Redis server.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the distributed event posted on the {@link EventBus}
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void distribute(final DistributedEvent event) {
|
||||||
|
if (redisTemplate != null) {
|
||||||
|
if (!NODE_ID.equals(event.getNodeId())) {
|
||||||
|
logDistributingEvent(event, SEND_DISTRIBUTION_CHANNEL);
|
||||||
|
event.setOriginNodeId(NODE_ID);
|
||||||
|
redisTemplate.convertAndSend(SEND_DISTRIBUTION_CHANNEL, event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logNotDistributingEvent(event, SEND_DISTRIBUTION_CHANNEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message listener callback method for the {@link MessageListenerAdapter}
|
||||||
|
* which calls the method in case a message is received from the Redis
|
||||||
|
* server of the type {@link DistributedEventWrapper}.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* the {@link DistributedEventWrapper} event which was received
|
||||||
|
* by the Redis client
|
||||||
|
* @param channel
|
||||||
|
* the on which the event was received
|
||||||
|
*/
|
||||||
|
public void handleMessage(final DistributedEvent event, final String channel) {
|
||||||
|
LOGGER.trace("retrieving event from redis {} on channel {}, posting to the local event bus", event, channel);
|
||||||
|
if (!NODE_ID.equals(event.getOriginNodeId())) {
|
||||||
|
event.setNodeId(NODE_ID);
|
||||||
|
eventBus.post(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a collection of all topics which this Redis message listener
|
||||||
|
* wants to subscribe
|
||||||
|
*/
|
||||||
|
public Collection<Topic> getTopics() {
|
||||||
|
final List<Topic> topics = new ArrayList<Topic>();
|
||||||
|
topics.add(new PatternTopic(SUB_DISTRIBUTION_CHANNEL));
|
||||||
|
return topics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logDistributingEvent(final Event event, final String channel) {
|
||||||
|
LOGGER.trace("distributing event {} from node {} to topic {}", event, NODE_ID, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logNotDistributingEvent(final Event event, final String channel) {
|
||||||
|
LOGGER.debug("no redis template configured, event {} will not be distributed to channel {} from node {}", event,
|
||||||
|
channel, NODE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testing purposes.
|
||||||
|
*
|
||||||
|
* @param redisTemplate
|
||||||
|
* the redisTemplate to set
|
||||||
|
*/
|
||||||
|
void setRedisTemplate(final RedisTemplate<String, Object> redisTemplate) {
|
||||||
|
this.redisTemplate = redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testing purposes.
|
||||||
|
*
|
||||||
|
* @param eventBus
|
||||||
|
* the eventBus to set
|
||||||
|
*/
|
||||||
|
void setEventBus(final EventBus eventBus) {
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the nodeId
|
||||||
|
*/
|
||||||
|
static String getNodeId() {
|
||||||
|
return NODE_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
222
hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/eventbus/EventDistributorTest.java
vendored
Executable file
222
hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/eventbus/EventDistributorTest.java
vendored
Executable file
@@ -0,0 +1,222 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache.eventbus;
|
||||||
|
|
||||||
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
|
||||||
|
import org.eclipse.hawkbit.eventbus.event.EntityEvent;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.listener.Topic;
|
||||||
|
import org.springframework.hateoas.Identifiable;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class EventDistributorTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RedisTemplate<String, Object> redisTemplateMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private EventBus eventBusMock;
|
||||||
|
|
||||||
|
private EventDistributor underTest;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
underTest = new EventDistributor();
|
||||||
|
underTest.setEventBus(eventBusMock);
|
||||||
|
underTest.setRedisTemplate(redisTemplateMock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void distributeDistributedEventSendsToRedis() {
|
||||||
|
|
||||||
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
||||||
|
underTest.distribute(event);
|
||||||
|
|
||||||
|
// origin node ID should be set by distributing the event
|
||||||
|
assertThat(event.getOriginNodeId()).isNotNull();
|
||||||
|
verify(redisTemplateMock).convertAndSend(anyString(), eq(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dontDistributeDistributedEventIfSameNode() {
|
||||||
|
final String knownNodeId = EventDistributor.getNodeId();
|
||||||
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
||||||
|
event.setNodeId(knownNodeId);
|
||||||
|
|
||||||
|
// test
|
||||||
|
underTest.distribute(event);
|
||||||
|
|
||||||
|
assertThat(event.getOriginNodeId()).isNull();
|
||||||
|
verify(redisTemplateMock, times(0)).convertAndSend(anyString(), eq(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void handleDistributedMessageFromRedis() {
|
||||||
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
||||||
|
final String knownChannel = "someChannel";
|
||||||
|
|
||||||
|
underTest.handleMessage(event, knownChannel);
|
||||||
|
|
||||||
|
assertThat(event.getNodeId()).isEqualTo(EventDistributor.getNodeId());
|
||||||
|
verify(eventBusMock).post(eq(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void handleDistributedMessageFilteredIfSameNodeId() {
|
||||||
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
||||||
|
final String knownChannel = "someChannel";
|
||||||
|
event.setOriginNodeId(EventDistributor.getNodeId());
|
||||||
|
|
||||||
|
underTest.handleMessage(event, knownChannel);
|
||||||
|
|
||||||
|
assertThat(event.getNodeId()).isNull();
|
||||||
|
verify(eventBusMock, times(0)).post(eq(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void subscribedTopicsContains2PatternTopics() {
|
||||||
|
final Collection<Topic> topics = underTest.getTopics();
|
||||||
|
assertThat(topics).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestEntityEvent implements EntityEvent {
|
||||||
|
|
||||||
|
private String originNodeId;
|
||||||
|
private String nodeId;
|
||||||
|
private final String tenant;
|
||||||
|
private final MyEntity entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param myEntity
|
||||||
|
*/
|
||||||
|
public TestEntityEvent(final MyEntity myEntity, final String tenant) {
|
||||||
|
this.entity = myEntity;
|
||||||
|
this.tenant = tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.eclipse.hawkbit.server.eventbus.event.Event#getRevision()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getRevision() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#getOriginNodeId()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getOriginNodeId() {
|
||||||
|
return originNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setOriginNodeId(
|
||||||
|
* java. lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setOriginNodeId(final String originNodeId) {
|
||||||
|
this.originNodeId = originNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.eclipse.hawkbit.server.eventbus.event.NodeAware#getNodeId()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setNodeId(java.
|
||||||
|
* lang. String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setNodeId(final String nodeId) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getEntity(java.
|
||||||
|
* lang. Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <E> E getEntity(final Class<E> entityClass) {
|
||||||
|
return entityClass.cast(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getEntity()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object getEntity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getTenant()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getTenant() {
|
||||||
|
return tenant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyEntity implements Identifiable<String> {
|
||||||
|
private final String id = "123";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.hateoas.Identifiable#getId()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
31
hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/redis/RedisPropertiesTest.java
vendored
Executable file
31
hawkbit-cache-redis/src/test/java/org/eclipse/hawkbit/cache/redis/RedisPropertiesTest.java
vendored
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache.redis;
|
||||||
|
|
||||||
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.cache.RedisProperties;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class RedisPropertiesTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setAndGetProps() {
|
||||||
|
final String knownHost = "bumlux";
|
||||||
|
final int knownPort = 1234;
|
||||||
|
|
||||||
|
final RedisProperties underTest = new RedisProperties();
|
||||||
|
underTest.setHost(knownHost);
|
||||||
|
underTest.setPort(knownPort);
|
||||||
|
|
||||||
|
assertThat(underTest.getHost()).isEqualTo(knownHost);
|
||||||
|
assertThat(underTest.getPort()).isEqualTo(knownPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
50
hawkbit-core/pom.xml
Executable file
50
hawkbit-core/pom.xml
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
|
||||||
|
All rights reserved. This program and the accompanying materials
|
||||||
|
are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
which accompanies this distribution, and is available at
|
||||||
|
http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-parent</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>hawkbit-core</artifactId>
|
||||||
|
<name>hawkBit :: Core</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>18.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.yandex.qatools.allure</groupId>
|
||||||
|
<artifactId>allure-junit-adaptor</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
42
hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java
Executable file
42
hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java
Executable 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;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the polling time for the controllers in HH:MM:SS notation.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@ConfigurationProperties(prefix = "hawkbit.controller")
|
||||||
|
public class ControllerPollProperties {
|
||||||
|
|
||||||
|
private String pollingTime = "00:05:00";
|
||||||
|
private String pollingOverdueTime = "00:05:00";
|
||||||
|
|
||||||
|
public String getPollingTime() {
|
||||||
|
return pollingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPollingTime(final String pollingTime) {
|
||||||
|
this.pollingTime = pollingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPollingOverdueTime() {
|
||||||
|
return pollingOverdueTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPollingOverdueTime(final String pollingOverdue) {
|
||||||
|
this.pollingOverdueTime = pollingOverdue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This resource bundles using specified basenames, to resource loading. This
|
||||||
|
* MessageSource implementation supports more than 1 properties file with the
|
||||||
|
* same name. All properties files will be merged.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DistributedResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(DistributedResourceBundleMessageSource.class);
|
||||||
|
private static final String PROPERTIES_SUFFIX = ".properties";
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to set Defaults. Default base name is classpath*:/messages.
|
||||||
|
* So all messages_ will be found.
|
||||||
|
*/
|
||||||
|
public DistributedResourceBundleMessageSource() {
|
||||||
|
setBasename("classpath*:/messages");
|
||||||
|
setDefaultEncoding("UTF-8");
|
||||||
|
setUseCodeAsDefaultMessage(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PropertiesHolder refreshProperties(final String filename, final PropertiesHolder propHolder) {
|
||||||
|
final Properties properties = new Properties();
|
||||||
|
long lastModified = -1;
|
||||||
|
if (!(resourceLoader instanceof ResourcePatternResolver)) {
|
||||||
|
LOGGER.warn(
|
||||||
|
"Resource Loader {} doensn't support getting multiple resources. Default properties mechanism will used",
|
||||||
|
resourceLoader.getClass().getName());
|
||||||
|
return super.refreshProperties(filename, propHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Resource[] resources = ((ResourcePatternResolver) resourceLoader)
|
||||||
|
.getResources(filename + PROPERTIES_SUFFIX);
|
||||||
|
for (final Resource resource : resources) {
|
||||||
|
final String sourcePath = resource.getURI().toString().replace(PROPERTIES_SUFFIX, "");
|
||||||
|
final PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);
|
||||||
|
properties.putAll(holder.getProperties());
|
||||||
|
if (lastModified < resource.lastModified()) {
|
||||||
|
lastModified = resource.lastModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final IOException ignored) {
|
||||||
|
LOGGER.warn("Resource with filname " + filename + " couldn't load", ignored);
|
||||||
|
}
|
||||||
|
return new PropertiesHolder(properties, lastModified);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResourceLoader(final ResourceLoader resourceLoader) {
|
||||||
|
this.resourceLoader = resourceLoader;
|
||||||
|
super.setResourceLoader(resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
hawkbit-core/src/main/java/org/eclipse/hawkbit/api/HostnameResolver.java
Executable file
28
hawkbit-core/src/main/java/org/eclipse/hawkbit/api/HostnameResolver.java
Executable 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.api;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve to reach the server url.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface HostnameResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
URL resolveHostname();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact.repository;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||||
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ArtifactRepository service interface.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ArtifactRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores an artifact into the repository.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to store the artifact
|
||||||
|
* @param content
|
||||||
|
* the content to store
|
||||||
|
* @param filename
|
||||||
|
* the filename of the artifact
|
||||||
|
* @param contentType
|
||||||
|
* the content type of the artifact
|
||||||
|
* @return the stored artifact
|
||||||
|
* @throws ArtifactStoreException
|
||||||
|
* in case storing of the artifact was not successful
|
||||||
|
*/
|
||||||
|
DbArtifact store(final InputStream content, final String filename, final String contentType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores an artifact into the repository.
|
||||||
|
*
|
||||||
|
* @param content
|
||||||
|
* the content to store
|
||||||
|
* @param filename
|
||||||
|
* the filename of the artifact
|
||||||
|
* @param contentType
|
||||||
|
* the content type of the artifact
|
||||||
|
* @param hash
|
||||||
|
* the hashes of the artifact to do hash-checks after storing the
|
||||||
|
* artifact, might be {@code null}
|
||||||
|
* @return the stored artifact
|
||||||
|
* @throws ArtifactStoreException
|
||||||
|
* in case storing of the artifact was not successful
|
||||||
|
* @throws HashNotMatchException
|
||||||
|
* in case {@code hash} is provided and not matching to the
|
||||||
|
* calculated hashes during storing
|
||||||
|
*/
|
||||||
|
DbArtifact store(final InputStream content, final String filename, final String contentType, DbArtifactHash hash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an artifact by its ID.
|
||||||
|
*
|
||||||
|
* @param artifactId
|
||||||
|
* the ID of the artifact to delete
|
||||||
|
*/
|
||||||
|
void deleteById(final String artifactId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an artifact by its SHA1 hash.
|
||||||
|
*
|
||||||
|
* @param sha1Hash
|
||||||
|
* the sha1-hash of the artifact to delete
|
||||||
|
*/
|
||||||
|
void deleteBySha1(final String sha1Hash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a {@link DbArtifact} from the store by it's SHA1 hash.
|
||||||
|
*
|
||||||
|
* @param sha1Hash
|
||||||
|
* the sha1-hash of the file to lookup.
|
||||||
|
* @return The artifact file object or {@code null} if no file exists.
|
||||||
|
*/
|
||||||
|
DbArtifact getArtifactBySha1(String sha1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a {@link DbArtifact} from the store by it's ID.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* the ID of the artifact to retrieve
|
||||||
|
* @return The artifact file object or {@code null} if no file exists.
|
||||||
|
*/
|
||||||
|
DbArtifact getArtifactById(final String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of {@link GridFSDBFile} from the store by all SHA1
|
||||||
|
* hashes.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to retrieve the artifacts from, ignore case.
|
||||||
|
* @param sha1Hashes
|
||||||
|
* the sha1-hashes of the files to lookup.
|
||||||
|
* @return list of artfiacts
|
||||||
|
*/
|
||||||
|
List<DbArtifact> getArtifactsBySha1(final List<String> sha1Hashes);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.artifact.repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ArtifactStoreException} is thrown in case storing of an artifact was
|
||||||
|
* not successful.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ArtifactStoreException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ArtifactStoreException with message and cause.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message of the exception
|
||||||
|
* @param cause
|
||||||
|
* the cause of the exception
|
||||||
|
*/
|
||||||
|
public ArtifactStoreException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ArtifactStoreException with message.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message of the exception
|
||||||
|
*/
|
||||||
|
public ArtifactStoreException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact.repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when provided hashes and hashes caluclated during storing are not
|
||||||
|
* matching.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HashNotMatchException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static final String SHA1 = "SHA-1";
|
||||||
|
public static final String MD5 = "MD5";
|
||||||
|
|
||||||
|
private final String hashFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a HashNotMatchException with message and cause.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message of the exception
|
||||||
|
* @param cause
|
||||||
|
* the cause of the exception
|
||||||
|
* @param hashFunction
|
||||||
|
* the hash function which caused this exception
|
||||||
|
*/
|
||||||
|
public HashNotMatchException(final String message, final Throwable cause, final String hashFunction) {
|
||||||
|
super(message, cause);
|
||||||
|
this.hashFunction = hashFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a HashNotMatchException with message.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message of the exception
|
||||||
|
* @param hashFunction
|
||||||
|
* the hash function which caused this exception
|
||||||
|
*/
|
||||||
|
public HashNotMatchException(final String message, final String hashFunction) {
|
||||||
|
super(message);
|
||||||
|
this.hashFunction = hashFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hashFunction
|
||||||
|
*/
|
||||||
|
public String getHashFunction() {
|
||||||
|
return hashFunction;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact.repository.model;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database representation of artifact.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DbArtifact {
|
||||||
|
|
||||||
|
private String artifactId;
|
||||||
|
|
||||||
|
private DbArtifactHash hashes;
|
||||||
|
|
||||||
|
private Long size;
|
||||||
|
|
||||||
|
private String contentType;
|
||||||
|
|
||||||
|
private InputStream fileInputStream;
|
||||||
|
|
||||||
|
private OutputStream fileOutputStream;
|
||||||
|
|
||||||
|
public void setArtifactId(final String artifactId) {
|
||||||
|
this.artifactId = artifactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getArtifactId() {
|
||||||
|
return artifactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbArtifactHash getHashes() {
|
||||||
|
return hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHashes(final DbArtifactHash hashes) {
|
||||||
|
this.hashes = hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(final Long size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(final String contentType) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileInputStream(final InputStream fileInputStream) {
|
||||||
|
this.fileInputStream = fileInputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getFileInputStream() {
|
||||||
|
return fileInputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getFileOutputStream() {
|
||||||
|
return fileOutputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileOutputStream(final OutputStream fileOutputStream) {
|
||||||
|
this.fileOutputStream = fileOutputStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* 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.artifact.repository.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database representation of artifact hash.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DbArtifactHash {
|
||||||
|
|
||||||
|
private String sha1;
|
||||||
|
|
||||||
|
private String md5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param sha1
|
||||||
|
* the sha1 hash
|
||||||
|
* @param md5
|
||||||
|
* the md5 hash
|
||||||
|
*/
|
||||||
|
public DbArtifactHash(final String sha1, final String md5) {
|
||||||
|
super();
|
||||||
|
this.sha1 = sha1;
|
||||||
|
this.md5 = md5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSha1(final String sha1) {
|
||||||
|
this.sha1 = sha1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMd5(final String md5) {
|
||||||
|
this.md5 = md5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSha1() {
|
||||||
|
return sha1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMd5() {
|
||||||
|
return md5;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/CacheConstants.java
vendored
Executable file
27
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/CacheConstants.java
vendored
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache Constants.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class CacheConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant for download cache id.
|
||||||
|
*/
|
||||||
|
public static final String DOWNLOAD_ID_CACHE = "DowonloadIdCache";
|
||||||
|
|
||||||
|
private CacheConstants() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
44
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/DownloadArtifactCache.java
vendored
Executable file
44
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/DownloadArtifactCache.java
vendored
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache Object for download a Artifact.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DownloadArtifactCache {
|
||||||
|
|
||||||
|
private final DownloadType downloadType;
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param downloadType
|
||||||
|
* the type for searching the artifact.
|
||||||
|
* @param id
|
||||||
|
* the searching id e.g. sha1, md5
|
||||||
|
*/
|
||||||
|
public DownloadArtifactCache(final DownloadType downloadType, final String id) {
|
||||||
|
super();
|
||||||
|
this.downloadType = downloadType;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownloadType getDownloadType() {
|
||||||
|
return downloadType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/DownloadType.java
vendored
Executable file
19
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/DownloadType.java
vendored
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the id which is saved.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum DownloadType {
|
||||||
|
BY_SHA1
|
||||||
|
}
|
||||||
40
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/TenancyCacheManager.java
vendored
Executable file
40
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/TenancyCacheManager.java
vendored
Executable 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.cache;
|
||||||
|
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface TenancyCacheManager extends CacheManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A direct access for retrieving the cache without including the current
|
||||||
|
* tenant key. This is necessary e.g. for retrieving caches not for the
|
||||||
|
* current tenant.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the name of the cache to retrieve directly
|
||||||
|
* @return the cache associated with the name without tenancy separation
|
||||||
|
*/
|
||||||
|
Cache getDirectCache(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evicts all caches for a given tenant. All caches under a certain tenant
|
||||||
|
* gets evicted.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant to evict caches
|
||||||
|
*/
|
||||||
|
void evictCaches(final String tenant);
|
||||||
|
|
||||||
|
}
|
||||||
102
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/TenantAwareCacheManager.java
vendored
Executable file
102
hawkbit-core/src/main/java/org/eclipse/hawkbit/cache/TenantAwareCacheManager.java
vendored
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* 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.cache;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link CacheManager} delegator which wraps the
|
||||||
|
* {@link CacheManager#getCache(String)} and
|
||||||
|
* {@link CacheManager#getCacheNames()} to include the
|
||||||
|
* {@link TenantAware#getCurrentTenant()} when accessing a cache, so caches are
|
||||||
|
* seperated.
|
||||||
|
*
|
||||||
|
* Additionally it also provide functionality to retrieve all caches overall
|
||||||
|
* tenants at once, for monitoring and system access.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TenantAwareCacheManager implements TenancyCacheManager {
|
||||||
|
|
||||||
|
private static final String TENANT_CACHE_DELIMITER = "|";
|
||||||
|
|
||||||
|
private final CacheManager delegate;
|
||||||
|
|
||||||
|
private final TenantAware tenantAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param delegate
|
||||||
|
* the {@link CacheManager} to delegate to.
|
||||||
|
* @param tenantAware
|
||||||
|
* the tenant aware to retrieve the current tenant
|
||||||
|
*/
|
||||||
|
public TenantAwareCacheManager(final CacheManager delegate, final TenantAware tenantAware) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.tenantAware = tenantAware;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cache getCache(final String name) {
|
||||||
|
final String currentTenant = tenantAware.getCurrentTenant().toUpperCase();
|
||||||
|
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return delegate.getCache(currentTenant + TENANT_CACHE_DELIMITER + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> getCacheNames() {
|
||||||
|
final String currentTenant = tenantAware.getCurrentTenant().toUpperCase();
|
||||||
|
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return getCacheNames(currentTenant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A direct access for retrieving all cache names overall tenants.
|
||||||
|
*
|
||||||
|
* @return all cache names without tenant check
|
||||||
|
*/
|
||||||
|
public Collection<String> getDirectCacheNames() {
|
||||||
|
return delegate.getCacheNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cache getDirectCache(final String name) {
|
||||||
|
return delegate.getCache(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.cache.TenancyCacheManager#evictCaches(java.
|
||||||
|
* lang. String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void evictCaches(final String tenant) {
|
||||||
|
getCacheNames(tenant)
|
||||||
|
.forEach(cachename -> delegate.getCache(tenant + TENANT_CACHE_DELIMITER + cachename).clear());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<String> getCacheNames(final String tenant) {
|
||||||
|
final String tenantWithDelimiter = tenant + TENANT_CACHE_DELIMITER;
|
||||||
|
return delegate.getCacheNames().parallelStream().filter(cacheName -> cacheName.startsWith(tenantWithDelimiter))
|
||||||
|
.map(cacheName -> cacheName.substring(tenantWithDelimiter.length())).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.eventbus;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.DeadEvent;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Catches all dead events by means of events with no fitting subscriber on the
|
||||||
|
* bus.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@EventSubscriber
|
||||||
|
public class DeadEventListener {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DeadEventListener.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for dead vents and prints them into LOG.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* to print
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void listen(final DeadEvent event) {
|
||||||
|
LOG.info("DeadEvent on bus! {}", event.getEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link BeanPostProcessor} implementation which registers all beans as a
|
||||||
|
* event bus subscriber if the classes are annotated with
|
||||||
|
* {@link EventSubscriber} and have at least one method annotated with the
|
||||||
|
* guava's {@link Subscribe} annoation.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class EventBusSubscriberProcessor implements BeanPostProcessor {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(EventBusSubscriberProcessor.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventBus eventBus;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.beans.factory.config.BeanPostProcessor#
|
||||||
|
* postProcessBeforeInitialization (java.lang.Object, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object postProcessBeforeInitialization(final Object bean, final String beanName) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.springframework.beans.factory.config.BeanPostProcessor#
|
||||||
|
* postProcessAfterInitialization( java.lang.Object, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object postProcessAfterInitialization(final Object bean, final String beanName) {
|
||||||
|
final Class<? extends Object> beanClass = bean.getClass();
|
||||||
|
final EventSubscriber eventSubscriber = beanClass.getAnnotation(EventSubscriber.class);
|
||||||
|
if (eventSubscriber != null) {
|
||||||
|
LOGGER.trace("Found bean {} with {} annotation ", bean.getClass().getName(),
|
||||||
|
EventSubscriber.class.getSimpleName());
|
||||||
|
final Method[] declaredMethods = beanClass.getDeclaredMethods();
|
||||||
|
for (final Method method : declaredMethods) {
|
||||||
|
final Subscribe subscriber = method.getAnnotation(Subscribe.class);
|
||||||
|
if (subscriber != null) {
|
||||||
|
LOGGER.trace("Found method {} for bean {} with {} annotation", method.getName(),
|
||||||
|
bean.getClass().getName(), Subscribe.class.getSimpleName());
|
||||||
|
eventBus.register(bean);
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eventSubscriber != null) {
|
||||||
|
LOGGER.debug("Found bean {} with {} annotation but without any method with necessary {} annotation",
|
||||||
|
bean.getClass().getName(), EventSubscriber.class.getSimpleName(), Subscribe.class.getSimpleName());
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* package private setter for testing purposes.
|
||||||
|
*
|
||||||
|
* @param eventBus
|
||||||
|
* the event bus
|
||||||
|
*/
|
||||||
|
void setEventBus(final EventBus eventBus) {
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/EventSubscriber.java
Executable file
42
hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/EventSubscriber.java
Executable 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.eventbus;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks an class as an event subscriber to listen on event on the event bus
|
||||||
|
* without explicit register this class to the event bus.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* @EventSubscriber
|
||||||
|
* public class MySubscriber {
|
||||||
|
* @Subscribe
|
||||||
|
* public void listen(MyEvent event) {
|
||||||
|
* System.out.println("event received: " + event);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target({ TYPE })
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Service
|
||||||
|
public @interface EventSubscriber {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract class of the {@link DistributedEvent} implementation which holds
|
||||||
|
* all the necessary information of distributing events to other nodes.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDistributedEvent implements DistributedEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final long revision;
|
||||||
|
private String originNodeId;
|
||||||
|
private String nodeId;
|
||||||
|
private final String tenant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param revision
|
||||||
|
* the revision of this event
|
||||||
|
* @param tenant
|
||||||
|
* the tenant for this event
|
||||||
|
*/
|
||||||
|
protected AbstractDistributedEvent(final long revision, final String tenant) {
|
||||||
|
this.revision = revision;
|
||||||
|
this.tenant = tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setOriginNodeId(java.
|
||||||
|
* lang. String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setOriginNodeId(final String originNodeId) {
|
||||||
|
this.originNodeId = originNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setNodeId(java.lang.
|
||||||
|
* String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setNodeId(final String nodeId) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#getOriginNodeId()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getOriginNodeId() {
|
||||||
|
return this.originNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.eclipse.hawkbit.server.eventbus.event.NodeAware#getNodeId()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getNodeId() {
|
||||||
|
return this.nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.eclipse.hawkbit.server.eventbus.event.Event#getRevision()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getRevision() {
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getTenant()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getTenant() {
|
||||||
|
return tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event that gets sent when the assignment of a distribution set to a target
|
||||||
|
* gets canceled.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CancelTargetAssignmentEvent {
|
||||||
|
|
||||||
|
private final String controllerId;
|
||||||
|
private final Long actionId;
|
||||||
|
private final URI targetAdress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link CancelTargetAssignmentEvent}.
|
||||||
|
*
|
||||||
|
* @param controllerId
|
||||||
|
* the ID of the controller
|
||||||
|
* @param actionId
|
||||||
|
* the action id of the assignment
|
||||||
|
* @param targetAdress
|
||||||
|
* the targetAdress of the target
|
||||||
|
*/
|
||||||
|
public CancelTargetAssignmentEvent(final String controllerId, final Long actionId, final URI targetAdress) {
|
||||||
|
this.controllerId = controllerId;
|
||||||
|
this.actionId = actionId;
|
||||||
|
this.targetAdress = targetAdress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the action id of the assignment
|
||||||
|
*/
|
||||||
|
public Long getActionId() {
|
||||||
|
return actionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the controllerId of the Target which has been assigned to the
|
||||||
|
* distribution set
|
||||||
|
*/
|
||||||
|
public String getControllerId() {
|
||||||
|
return controllerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the targetr adress.
|
||||||
|
*/
|
||||||
|
public URI getTargetAdress() {
|
||||||
|
return targetAdress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TargetAssignDistributionSetEvent [targetAdress=" + targetAdress + ", controllerId=" + controllerId
|
||||||
|
+ ", actionId=" + actionId + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.eventbus.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Events to be published to refresh data on UI.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum CustomEvents {
|
||||||
|
|
||||||
|
TARGETS_CREATED_EVENT,
|
||||||
|
|
||||||
|
DISTRIBUTION_CREATED_EVENT
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks an event to as an distributed event which will be distributed to other
|
||||||
|
* nodes.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface DistributedEvent extends Event, NodeAware, Serializable {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.eventbus.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event that contains an updated download progress for a given Action.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DownloadProgressEvent extends AbstractDistributedEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final Long statusId;
|
||||||
|
private final int progressPercent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant for this event
|
||||||
|
* @param statusId
|
||||||
|
* of {@link UpdateActionStatus}
|
||||||
|
* @param progressPercent
|
||||||
|
* number (1-100)
|
||||||
|
*/
|
||||||
|
public DownloadProgressEvent(final String tenant, final Long statusId, final int progressPercent) {
|
||||||
|
// the revision of the DownloadProgressEvent is just equal the
|
||||||
|
// progressPercentage due the
|
||||||
|
// percentage is going from 0 to 100.
|
||||||
|
super(statusId, tenant);
|
||||||
|
this.statusId = statusId;
|
||||||
|
this.progressPercent = progressPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the statusId
|
||||||
|
*/
|
||||||
|
public Long getStatusId() {
|
||||||
|
return statusId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the progressPercent
|
||||||
|
*/
|
||||||
|
public int getProgressPercent() {
|
||||||
|
return progressPercent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event interface which declares event types that an entity has been
|
||||||
|
* changed. {@link EntityEvent}s should not implement {@link DistributedEvent}
|
||||||
|
* due all {@link EntityEvent}s will be distributed to other nodes.
|
||||||
|
*
|
||||||
|
* Retrieving an {@link EntityEvent} on a different node the entity will be load
|
||||||
|
* lazy.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface EntityEvent extends Event, NodeAware {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A typesafe way to retrieve the entity from the event, which might be
|
||||||
|
* loaded lazy in case the event has been distributed from another node.
|
||||||
|
*
|
||||||
|
* @param entityClass
|
||||||
|
* the class of the entity to retrieve
|
||||||
|
* @return the entity might be lazy loaded. Might be {@code null} in case
|
||||||
|
* the entity e.g. is queried lazy on a different node and has been
|
||||||
|
* already deleted from the database
|
||||||
|
* @throws ClassCastException
|
||||||
|
* in case a wrong entity class is given for this event
|
||||||
|
*/
|
||||||
|
<E> E getEntity(Class<E> entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An unsafe way to retrieve the entity from this event which might be
|
||||||
|
* loaded lazy in case the event has been distributed from another node.
|
||||||
|
*
|
||||||
|
* @return the entity might be lazy loaded. Might be {@code null} in case
|
||||||
|
* the entity e.g. is queried lazy on a different node and has been
|
||||||
|
* already deleted from the database
|
||||||
|
*/
|
||||||
|
Object getEntity();
|
||||||
|
}
|
||||||
32
hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/Event.java
Executable file
32
hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/Event.java
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.eventbus.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event declaration which holds an revision for each event so consumers have
|
||||||
|
* the chance to know if they might already retrieved an newer event.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the revision of this event which should be increment or each new
|
||||||
|
* event in case the event have a causalität. Might be {@code -1} in
|
||||||
|
* case the events does not provide any revision.
|
||||||
|
*/
|
||||||
|
long getRevision();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the tenant of the entity.
|
||||||
|
*/
|
||||||
|
String getTenant();
|
||||||
|
}
|
||||||
52
hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/NodeAware.java
Executable file
52
hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/NodeAware.java
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to be implemented by events which are distributed to other nodes
|
||||||
|
* where it's necessary to know which node sent an event and which nodes
|
||||||
|
* retrieved the event from which node. Using the EventDistributor the
|
||||||
|
* implementation only needs to contain the necessary node IDs, setting and
|
||||||
|
* retrieving the node IDs is transparent by the EventDistributor so the event
|
||||||
|
* distributor does not hang in an endless loop of distributing the events which
|
||||||
|
* self posted.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface NodeAware {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the origin node ID in case the event has been forwarded to other
|
||||||
|
* nodes or {@code null} if the event has not been forwarded to
|
||||||
|
* other nodes
|
||||||
|
*/
|
||||||
|
String getOriginNodeId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param originNodeId
|
||||||
|
* the origin node ID where this event has been sent originally
|
||||||
|
*/
|
||||||
|
void setOriginNodeId(String originNodeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the node ID which is processing this event locally, set by the
|
||||||
|
* EventDistributor so he can determine if this event has been
|
||||||
|
* received by another node and is processing on the current node.
|
||||||
|
*/
|
||||||
|
String getNodeId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nodeId
|
||||||
|
* the ID of the node this event is processing.
|
||||||
|
*/
|
||||||
|
void setNodeId(String nodeId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TargetDeletedEvent extends AbstractDistributedEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final long targetId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tenant
|
||||||
|
* the tenant for this event
|
||||||
|
* @param targetId
|
||||||
|
* the ID of the target which has been deleted
|
||||||
|
*/
|
||||||
|
public TargetDeletedEvent(final String tenant, final long targetId) {
|
||||||
|
super(-1, tenant);
|
||||||
|
this.targetId = targetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the targetId
|
||||||
|
*/
|
||||||
|
public long getTargetId() {
|
||||||
|
return targetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user