Merge branch 'master' into Feature_Improve_Code_Quality

Conflicts:
	hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java
	hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java
	hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java
	hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListener.java
	hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java


Signed-off-by: Michael Hirsch <michael.hirsch@bosch-si.com>
This commit is contained in:
Michael Hirsch
2016-07-25 10:08:24 +02:00
805 changed files with 31882 additions and 22829 deletions

2
.gitignore vendored
View File

@@ -53,3 +53,5 @@ local.properties
# Maven
maven.properties
/*/maven.properties
hawkbit-repository/hawkbit-repository-jpa/.springBeans

View File

@@ -11,3 +11,10 @@
### REST API model changes for clients
- ENTITYPagedList classes have been removed; generic PagedList used instead (e.g. PagedList<TargetRest> instead of TargetPagedList).
- ENTITYsrest classes have been removed; List<ENTITYrest> used instead (e.g. List<TargetRest> instead of TargetsRest)
### Renamed api annotations
- Annotation `org.eclipse.hawkbit.rest.resource.EnableRestResources` have changed to `org.eclipse.hawkbit.mgmt.annotation.EnableMgmtApi`
- Annotation `org.eclipse.hawkbit.ddi.resource.EnableDirectDeviceApi` have changed to `org.eclipse.hawkbit.ddi.annotation.EnableDdiApi`
### Renamed maven modules
- Module hawkbit-mgmt-api-client have changed to hawkbit-example-mgmt-simulator

View File

@@ -1,5 +1,7 @@
Build: [![Circle CI](https://circleci.com/gh/eclipse/hawkbit.svg?style=svg)](https://circleci.com/gh/eclipse/hawkbit)
<img src=hawkbit_logo.png width=533 height=246 />
# Eclipse.IoT hawkBit - Update Server
[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.
@@ -41,9 +43,9 @@ $ java -jar ./examples/hawkbit-example-app/target/hawkbit-example-app-#version#.
$ java -jar ./examples/hawkbit-device-simulator/target/hawkbit-device-simulator-#version#.jar
```
#### Generate Getting Started data
[Example Management API Client](examples/hawkbit-mgmt-api-client)
[Example Management API Client](examples/hawkbit-example-mgmt-simulator)
```
$ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#version#.jar
$ java -jar ./examples/hawkbit-example-mgmt-simulator/target/hawkbit-example-mgmt-simulator-#version#.jar
```
# Releases and Roadmap
@@ -57,16 +59,22 @@ $ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#v
# Modules
`hawkbit-core` : internal interfaces and utility classes..
`hawkbit-security-core` : authentication and authorization.
`hawkbit-security-integration` : authentication and authorization integrated with the APIs.
`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 implementation based on SQL for all meta-data.
`hawkbit-http-security` : implementation for security filters for HTTP.
`hawkbit-rest-api` : API classes for the REST Management API.
`hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API.
`hawkbit-ui` : Vaadin UI.
`hawkbit-cache-redis` : spring cache manager configuration and implementation with redis, distributed cache and distributed events.
* `examples` : hawkBit examples
* `hawkbit-artifact-repository-mongo` : Artifact repository implementation to mongoDB.
* `hawkbit-autoconfigure` : Spring-boot auto-configuration.
* `hawkbit-cache-redis` : Spring cache manager configuration and implementation with redis, distributed cache and distributed events.
* `hawkbit-core` : Core elements for internal interfaces and utility classes.
* `hawkbit-ddi-api` : The hawkBit DDI API.
* `hawkbit-ddi-dl-api` : The hawkBit DDI Download API.
* `hawkbit-ddi-resource` : Implementation of the hawkBit DDI API
* `hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API.
* `hawkbit-dmf-api` : API for the Device Management Integration.
* `hawkbit-http-security` : Implementation for security filters for HTTP.
* `hawkbit-mgmt-api` : The hawkBit Management API
* `hawkbit-mgmt-resource` : Implementation of the hawkBit Management API
* `hawkbit-repository` : Repository implementation based on SQL for all meta-data.
* `hawkbit-rest-core` : Core elements for the rest modules.
* `hawkbit-security-core` : Core security elements.
* `hawkbit-security-integration` : Security integration elements to integrate security into hawkBit.
* `hawkbit-test-report` : Test reports
* `hawkbit-ui` : Vaadin UI.

View File

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

View File

@@ -79,6 +79,11 @@
<artifactId>hawkbit-http-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring -->
<dependency>

View File

@@ -8,11 +8,10 @@ package org.eclipse.hawkbit.app;
* http://www.eclipse.org/legal/epl-v10.html
*/
import org.eclipse.hawkbit.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.EnableJpaRepository;
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
/**
* A {@link SpringBootApplication} annotated class with a main method to start.
@@ -20,10 +19,10 @@ import org.springframework.context.annotation.Import;
*
*/
@SpringBootApplication
@Import({ RepositoryApplicationConfiguration.class })
@EnableHawkbitManagedSecurityConfiguration
// Exception squid:S1118 - Spring boot standard behavior
@SuppressWarnings({ "squid:S1118" })
@EnableJpaRepository
public class Start {
/**
* Main method to start the spring-boot application.

View File

@@ -19,7 +19,7 @@
</parent>
<artifactId>hawkbit-device-simulator</artifactId>
<name>hawkBit :: Device Simulator</name>
<name>hawkBit-example :: Device Simulator</name>
<description>Device Management Federation API based simulator</description>
<build>
@@ -71,6 +71,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
@@ -82,16 +86,6 @@
<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>com.vaadin</groupId>
@@ -106,10 +100,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@@ -117,12 +107,10 @@
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.14.1</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.12.1</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>

View File

@@ -27,7 +27,7 @@ public abstract class AbstractSimulatedDevice {
private UpdateStatus updateStatus = new UpdateStatus(ResponseStatus.SUCCESSFUL, "Simulation complete!");
private Protocol protocol = Protocol.DMF_AMQP;
private String targetSecurityToken;
private int pollDelaySec;
private int nextPollCounterSec;
/**
@@ -84,13 +84,30 @@ public abstract class AbstractSimulatedDevice {
* the ID of the simulated device
* @param tenant
* the tenant of the simulated device
* @param int
* pollDelaySec
*/
AbstractSimulatedDevice(final String id, final String tenant, final Protocol protocol) {
AbstractSimulatedDevice(final String id, final String tenant, final Protocol protocol, final int pollDelaySec) {
this.id = id;
this.tenant = tenant;
this.status = Status.UNKNWON;
this.progress = 0.0;
this.protocol = protocol;
this.pollDelaySec = pollDelaySec;
}
/**
* Can be called by a scheduler to trigger a device polling, like in real
* scenarios devices are frequently asking for updates etc.
*/
public abstract void poll();
public int getPollDelaySec() {
return pollDelaySec;
}
public void setPollDelaySec(final int pollDelaySec) {
this.pollDelaySec = pollDelaySec;
}
/**

View File

@@ -23,7 +23,6 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class);
private final int pollDelaySec;
private final ControllerResource controllerResource;
private final DeviceSimulatorUpdater deviceUpdater;
@@ -45,11 +44,9 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
*/
public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec,
final ControllerResource controllerResource, final DeviceSimulatorUpdater deviceUpdater) {
super(id, tenant, Protocol.DDI_HTTP);
this.pollDelaySec = pollDelaySec;
super(id, tenant, Protocol.DDI_HTTP, pollDelaySec);
this.controllerResource = controllerResource;
this.deviceUpdater = deviceUpdater;
setNextPollCounterSec(pollDelaySec);
}
@Override
@@ -58,13 +55,10 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
removed = true;
}
public int getPollDelaySec() {
return pollDelaySec;
}
/**
* Polls the base URL for the DDI API interface.
*/
@Override
public void poll() {
if (!removed) {
final String basePollJson = controllerResource.get(getTenant(), getId());

View File

@@ -8,10 +8,13 @@
*/
package org.eclipse.hawkbit.simulator;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
/**
* A simulated device using the DMF API of the hawkBit update server.
*/
public class DMFSimulatedDevice extends AbstractSimulatedDevice {
private final SpSenderService spSenderService;
/**
* @param id
@@ -19,8 +22,15 @@ public class DMFSimulatedDevice extends AbstractSimulatedDevice {
* @param tenant
* the tenant of the simulated device
*/
public DMFSimulatedDevice(final String id, final String tenant) {
super(id, tenant, Protocol.DMF_AMQP);
public DMFSimulatedDevice(final String id, final String tenant, final SpSenderService spSenderService,
final int pollDelaySec) {
super(id, tenant, Protocol.DMF_AMQP, pollDelaySec);
this.spSenderService = spSenderService;
}
@Override
public void poll() {
spSenderService.createOrUpdateThing(super.getTenant(), super.getId());
}
}

View File

@@ -9,8 +9,8 @@
package org.eclipse.hawkbit.simulator;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -25,7 +25,7 @@ import org.springframework.stereotype.Service;
@Service
public class DeviceSimulatorRepository {
private final Map<DeviceKey, AbstractSimulatedDevice> devices = new LinkedHashMap<>();
private final Map<DeviceKey, AbstractSimulatedDevice> devices = new ConcurrentHashMap<>();
@Autowired
private SimulatedDeviceFactory deviceFactory;

View File

@@ -10,8 +10,6 @@ package org.eclipse.hawkbit.simulator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.DigestOutputStream;
import java.security.KeyManagementException;
@@ -34,6 +32,7 @@ import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.eclipse.hawkbit.dmf.json.model.Artifact;
import org.eclipse.hawkbit.dmf.json.model.Artifact.UrlProtocol;
import org.eclipse.hawkbit.dmf.json.model.SoftwareModule;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
@@ -59,7 +58,7 @@ import com.google.common.io.ByteStreams;
public class DeviceSimulatorUpdater {
private static final Logger LOGGER = LoggerFactory.getLogger(DeviceSimulatorUpdater.class);
private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4);
private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(8);
@Autowired
private SpSenderService spSenderService;
@@ -99,7 +98,8 @@ public class DeviceSimulatorUpdater {
// plug and play - non existing device will be auto created
if (device == null) {
device = repository.add(deviceFactory.createSimulatedDevice(id, tenant, Protocol.DMF_AMQP, -1, null, null));
device = repository
.add(deviceFactory.createSimulatedDevice(id, tenant, Protocol.DMF_AMQP, 1800, null, null));
}
device.setProgress(0.0);
@@ -149,6 +149,8 @@ public class DeviceSimulatorUpdater {
eventbus.post(new ProgressUpdate(device));
return;
}
// download is 80% of the game after all
device.setProgress(0.8);
}
final double newProgress = device.getProgress() + 0.2;
@@ -195,18 +197,14 @@ public class DeviceSimulatorUpdater {
private static void handleArtifacts(final String targetToken, final List<UpdateStatus> status,
final Artifact artifact) {
artifact.getUrls().entrySet().forEach(entry -> {
switch (entry.getKey()) {
case HTTP:
case HTTPS:
status.add(downloadUrl(entry.getValue(), targetToken, artifact.getHashes().getSha1(),
artifact.getSize()));
break;
default:
// not supported yet
break;
}
});
if (artifact.getUrls().containsKey(UrlProtocol.HTTPS)) {
status.add(downloadUrl(artifact.getUrls().get(UrlProtocol.HTTPS), targetToken,
artifact.getHashes().getSha1(), artifact.getSize()));
} else if (artifact.getUrls().containsKey(UrlProtocol.HTTP)) {
status.add(downloadUrl(artifact.getUrls().get(UrlProtocol.HTTP), targetToken,
artifact.getHashes().getSha1(), artifact.getSize()));
}
}
private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash,
@@ -233,18 +231,15 @@ public class DeviceSimulatorUpdater {
return new UpdateStatus(ResponseStatus.ERROR, message);
}
final File tempFile = File.createTempFile("uploadFile", null);
// Exception squid:S2070 - not used for hashing sensitive
// data
@SuppressWarnings("squid:S2070")
final MessageDigest md = MessageDigest.getInstance("SHA-1");
try (final DigestOutputStream dos = new DigestOutputStream(new FileOutputStream(tempFile), md)) {
try (final BufferedOutputStream bdos = new BufferedOutputStream(dos)) {
try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
overallread = ByteStreams.copy(bis, bdos);
}
}
} finally {
if (tempFile != null && !tempFile.delete()) {
LOGGER.error("Could not delete temporary file: {}", tempFile);
try (final BufferedOutputStream bdos = new BufferedOutputStream(
new DigestOutputStream(ByteStreams.nullOutputStream(), md))) {
try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
overallread = ByteStreams.copy(bis, bdos);
}
}
@@ -262,7 +257,7 @@ public class DeviceSimulatorUpdater {
}
} catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
LOGGER.error("Failed to download {} with {}", url, e.getMessage());
LOGGER.error("Failed to download" + url, e);
return new UpdateStatus(ResponseStatus.ERROR, "Failed to download " + url + ": " + e.getMessage());
}
@@ -272,6 +267,10 @@ public class DeviceSimulatorUpdater {
}
private static String hideTokenDetails(final String targetToken) {
if (targetToken == null) {
return "<NULL!>";
}
if (targetToken.isEmpty()) {
return "<EMTPTY!>";
}

View File

@@ -8,12 +8,11 @@
*/
package org.eclipse.hawkbit.simulator;
import java.util.List;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
import org.slf4j.Logger;
@@ -51,18 +50,17 @@ public class NextPollTimeController {
private class NextPollUpdaterRunnable implements Runnable {
@Override
public void run() {
final List<AbstractSimulatedDevice> devices = repository.getAll().stream()
.filter(device -> device instanceof DDISimulatedDevice).collect(Collectors.toList());
final Collection<AbstractSimulatedDevice> devices = repository.getAll();
devices.forEach(device -> {
int nextCounter = device.getNextPollCounterSec() - 1;
if (nextCounter < 0 && device instanceof DDISimulatedDevice) {
if (nextCounter < 0) {
try {
pollService.submit(() -> ((DDISimulatedDevice) device).poll());
pollService.submit(() -> device.poll());
} catch (final IllegalStateException e) {
LOGGER.trace("Device could not be polled", e);
}
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
nextCounter = device.getPollDelaySec();
}
device.setNextPollCounterSec(nextCounter);

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.simulator;
import java.net.URL;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.http.ControllerResource;
import org.eclipse.hawkbit.simulator.http.GatewayTokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,6 +29,9 @@ public class SimulatedDeviceFactory {
@Autowired
private DeviceSimulatorUpdater deviceUpdater;
@Autowired
private SpSenderService spSenderService;
/**
* Creating a simulated devices.
*
@@ -41,7 +45,7 @@ public class SimulatedDeviceFactory {
*/
public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant,
final Protocol protocol) {
return createSimulatedDevice(id, tenant, protocol, 30, null, null);
return createSimulatedDevice(id, tenant, protocol, 1800, null, null);
}
/**
@@ -55,7 +59,7 @@ public class SimulatedDeviceFactory {
* the protocol which should be used be the simulated device
* @param pollDelaySec
* the poll delay time in seconds which should be used for
* {@link DDISimulatedDevice}s
* {@link DDISimulatedDevice}s and {@link DMFSimulatedDevice}
* @param baseEndpoint
* the http base endpoint which should be used for
* {@link DDISimulatedDevice}s
@@ -68,7 +72,7 @@ public class SimulatedDeviceFactory {
final int pollDelaySec, final URL baseEndpoint, final String gatewayToken) {
switch (protocol) {
case DMF_AMQP:
return new DMFSimulatedDevice(id, tenant);
return new DMFSimulatedDevice(id, tenant, spSenderService, pollDelaySec);
case DDI_HTTP:
final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger())
.requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC)

View File

@@ -66,7 +66,7 @@ public class SimulationController {
@RequestParam(value = "tenant", defaultValue = "DEFAULT") final String tenant,
@RequestParam(value = "api", defaultValue = "dmf") final String api,
@RequestParam(value = "endpoint", defaultValue = "http://localhost:8080") final String endpoint,
@RequestParam(value = "polldelay", defaultValue = "30") final int pollDelay,
@RequestParam(value = "polldelay", defaultValue = "1800") final int pollDelay,
@RequestParam(value = "gatewaytoken", defaultValue = "") final String gatewayToken)
throws MalformedURLException {
@@ -86,10 +86,6 @@ public class SimulationController {
final String deviceId = name + i;
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint),
gatewayToken));
if (protocol == Protocol.DMF_AMQP) {
spSenderService.createOrUpdateThing(tenant, deviceId);
}
}
return ResponseEntity.ok("Updated " + amount + " DMF connected targets!");

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.simulator;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.hibernate.validator.constraints.NotEmpty;
@@ -68,9 +69,9 @@ public class SimulationProperties {
private String endpoint = "http://localhost:8080";
/**
* Poll time in case of DDI API based simulation.
* Poll time in {@link TimeUnit#SECONDS} for simulated devices.
*/
private int pollDelay = 30;
private int pollDelay = (int) TimeUnit.MINUTES.toSeconds(30);
/**
* Optional gateway token for DDI API based simulation.

View File

@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.simulator;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,10 +53,6 @@ public class SimulatorStartup implements ApplicationListener<ContextRefreshedEve
} catch (final MalformedURLException e) {
LOGGER.error("Creation of simulated device at startup failed.", e);
}
if (autostart.getApi() == Protocol.DMF_AMQP) {
spSenderService.createOrUpdateThing(autostart.getTenant(), deviceId);
}
}
});
}

View File

@@ -8,54 +8,107 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.core.QueueBuilder;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
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.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;
/**
* The spring AMQP configuration to use a AMQP for communication with SP update
* server.
*
*
*
*/
@Configuration
@EnableConfigurationProperties(AmqpProperties.class)
public class AmqpConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(AmqpConfiguration.class);
@Autowired
protected AmqpProperties amqpProperties;
@Autowired
private ConnectionFactory connectionFactory;
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* Create jackson message converter bean.
*
* @return the jackson message converter
* @return {@link RabbitTemplate} with automatic retry, published confirms
* and {@link Jackson2JsonMessageConverter}.
*/
@Bean
public MessageConverter jsonMessageConverter() {
final Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter);
return jackson2JsonMessageConverter;
public RabbitTemplate rabbitTemplate() {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
final RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy());
rabbitTemplate.setRetryTemplate(retryTemplate);
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
LOGGER.debug("Message with correlation ID {} confirmed by broker.", correlationData.getId());
} else {
LOGGER.error("Broker is unable to handle message with correlation ID {} : {}", correlationData.getId(),
cause);
}
});
return rabbitTemplate;
}
@Configuration
protected static class RabbitConnectionFactoryCreator {
/**
* {@link ConnectionFactory} with enabled publisher confirms and
* heartbeat.
*
* @param config
* with standard {@link RabbitProperties}
* @return {@link ConnectionFactory}
*/
@Bean
public ConnectionFactory rabbitConnectionFactory(final RabbitProperties config) {
final CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setRequestedHeartBeat(60);
factory.setPublisherConfirms(true);
final String addresses = config.getAddresses();
factory.setAddresses(addresses);
if (config.getHost() != null) {
factory.setHost(config.getHost());
factory.setPort(config.getPort());
}
if (config.getUsername() != null) {
factory.setUsername(config.getUsername());
}
if (config.getPassword() != null) {
factory.setPassword(config.getPassword());
}
if (config.getVirtualHost() != null) {
factory.setVirtualHost(config.getVirtualHost());
}
return factory;
}
}
/**
@@ -65,9 +118,12 @@ public class AmqpConfiguration {
* @return the queue
*/
@Bean
public Queue receiverConnectorQueueFromSp() {
return new Queue(amqpProperties.getReceiverConnectorQueueFromSp(), true, false, false,
getDeadLetterExchangeArgs());
public Queue receiverConnectorQueueFromHawkBit() {
final Map<String, Object> arguments = getDeadLetterExchangeArgs();
arguments.putAll(getTTLMaxArgs());
return QueueBuilder.nonDurable(amqpProperties.getReceiverConnectorQueueFromSp()).autoDelete()
.withArguments(arguments).build();
}
/**
@@ -77,19 +133,19 @@ public class AmqpConfiguration {
*/
@Bean
public FanoutExchange exchangeQueueToConnector() {
return new FanoutExchange(amqpProperties.getSenderForSpExchange());
return new FanoutExchange(amqpProperties.getSenderForSpExchange(), false, true);
}
/**
* Create the Binding
* {@link AmqpConfiguration#receiverConnectorQueueFromSp()} to
* {@link AmqpConfiguration#receiverConnectorQueueFromHawkBit()} to
* {@link AmqpConfiguration#exchangeQueueToConnector()}.
*
* @return the binding and create the queue and exchange
*/
@Bean
public Binding bindReceiverQueueToSpExchange() {
return BindingBuilder.bind(receiverConnectorQueueFromSp()).to(exchangeQueueToConnector());
return BindingBuilder.bind(receiverConnectorQueueFromHawkBit()).to(exchangeQueueToConnector());
}
/**
@@ -99,7 +155,7 @@ public class AmqpConfiguration {
*/
@Bean
public Queue deadLetterQueue() {
return new Queue(amqpProperties.getDeadLetterQueue(), true, false, true);
return QueueBuilder.nonDurable(amqpProperties.getDeadLetterQueue()).withArguments(getTTLMaxArgs()).build();
}
/**
@@ -109,7 +165,7 @@ public class AmqpConfiguration {
*/
@Bean
public FanoutExchange exchangeDeadLetter() {
return new FanoutExchange(amqpProperties.getDeadLetterExchange());
return new FanoutExchange(amqpProperties.getDeadLetterExchange(), false, true);
}
/**
@@ -131,10 +187,10 @@ public class AmqpConfiguration {
@Bean(name = { "listenerContainerFactory" })
public SimpleRabbitListenerContainerFactory listenerContainerFactory() {
final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
containerFactory.setDefaultRequeueRejected(false);
containerFactory.setDefaultRequeueRejected(true);
containerFactory.setConnectionFactory(connectionFactory);
containerFactory.setConcurrentConsumers(20);
containerFactory.setMaxConcurrentConsumers(20);
containerFactory.setConcurrentConsumers(3);
containerFactory.setMaxConcurrentConsumers(10);
containerFactory.setPrefetchCount(20);
return containerFactory;
}
@@ -145,4 +201,11 @@ public class AmqpConfiguration {
return args;
}
private static Map<String, Object> getTTLMaxArgs() {
final Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", Duration.ofDays(1).toMillis());
args.put("x-max-length", 100_000);
return args;
}
}

View File

@@ -82,21 +82,4 @@ public class MessageService {
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.");
}
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -55,7 +56,7 @@ public abstract class ReceiverService extends MessageService {
if (contentType != null && contentType.contains("json")) {
return;
}
throw new IllegalArgumentException("Content-Type is not JSON compatible");
throw new AmqpRejectAndDontRequeueException("Content-Type is not JSON compatible");
}
}

View File

@@ -8,9 +8,14 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import java.util.UUID;
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.amqp.rabbit.support.CorrelationData;
import org.springframework.amqp.support.converter.AbstractJavaTypeMapper;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +27,8 @@ import org.springframework.beans.factory.annotation.Autowired;
*/
public abstract class SenderService extends MessageService {
private static final Logger LOGGER = LoggerFactory.getLogger(SenderService.class);
/**
* Constructor for sender service.
*
@@ -40,18 +47,26 @@ public abstract class SenderService extends MessageService {
/**
* Send a message if the message is not null.
*
* @param adress
* @param address
* 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) {
public void sendMessage(final String address, final Message message) {
if (message == null) {
return;
}
message.getMessageProperties().getHeaders().remove(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME);
rabbitTemplate.setExchange(adress);
rabbitTemplate.send(message);
final String correlationId = UUID.randomUUID().toString();
message.getMessageProperties().setCorrelationId(correlationId.getBytes());
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Sending message {} to exchange {} with correlationId {}", message, address, correlationId);
} else {
LOGGER.debug("Sending message to exchange {} with correlationId {}", address, correlationId);
}
rabbitTemplate.send(address, null, message, new CorrelationData(correlationId));
}
/**

View File

@@ -35,14 +35,21 @@ import com.google.common.collect.Lists;
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;
private final DeviceSimulatorUpdater deviceUpdater;
/**
* Constructor.
*
* @param rabbitTemplate
* for sending messages
* @param amqpProperties
* for amqp configuration
* @param spSenderService
* to send messages
* @param deviceUpdater
* simulator service for updates
*/
@Autowired
public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties,

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.simulator.event;
import java.util.List;
import java.util.Collection;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
@@ -20,7 +20,7 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
*/
public class NextPollCounterUpdate {
private final List<AbstractSimulatedDevice> devices;
private final Collection<AbstractSimulatedDevice> devices;
/**
* Creates poll timer update event.
@@ -28,14 +28,14 @@ public class NextPollCounterUpdate {
* @param devices
* the devices which progress has been updated
*/
public NextPollCounterUpdate(final List<AbstractSimulatedDevice> devices) {
public NextPollCounterUpdate(final Collection<AbstractSimulatedDevice> devices) {
this.devices = devices;
}
/**
* @return the devices of the event
*/
public List<AbstractSimulatedDevice> getDevices() {
public Collection<AbstractSimulatedDevice> getDevices() {
return devices;
}

View File

@@ -76,7 +76,6 @@ public class GenerateDialog extends Window {
pollDelayTextField = createRequiredTextfield("poll delay (sec)", new ObjectProperty<Integer>(10),
FontAwesome.CLOCK_O, new RangeValidator<Integer>("Must be between 1 and 60", Integer.class, 1, 60));
pollDelayTextField.setVisible(false);
pollUrlTextField = createRequiredTextfield("base poll URL endpoint", "http://localhost:8080",
FontAwesome.FLAG_O, new RegexpValidator(
@@ -193,7 +192,6 @@ public class GenerateDialog extends Window {
protocolGroup.select(Protocol.DMF_AMQP);
protocolGroup.addValueChangeListener(event -> {
final boolean directDeviceOptionSelected = event.getProperty().getValue().equals(Protocol.DDI_HTTP);
pollDelayTextField.setVisible(directDeviceOptionSelected);
pollUrlTextField.setVisible(directDeviceOptionSelected);
gatewayTokenTextField.setVisible(directDeviceOptionSelected);
});

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.simulator.ui;
import java.util.List;
import java.util.Collection;
import java.util.Locale;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
@@ -167,7 +167,7 @@ public class SimulatorView extends VerticalLayout implements View {
@SuppressWarnings("unchecked")
@Subscribe
public void pollCounterUpdate(final NextPollCounterUpdate update) {
final List<AbstractSimulatedDevice> devices = update.getDevices();
final Collection<AbstractSimulatedDevice> devices = update.getDevices();
this.getUI().access(() -> devices.forEach(device -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {

View File

@@ -24,7 +24,6 @@ spring.rabbitmq.virtualHost=/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.dynamic=true
spring.rabbitmq.listener.prefetch=100
security.basic.enabled=false
server.port=8083

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit.eventbus.DeadEventListener" level="WARN" />
<Logger name="org.springframework.boot.actuate.audit.listener.AuditListener" level="WARN" />
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR" />
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</configuration>

View File

@@ -17,7 +17,7 @@
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-example-app</artifactId>
<name>hawkBit :: Example App</name>
<name>hawkBit-example :: UI Application</name>
<build>
<plugins>
@@ -64,7 +64,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-rest-resource</artifactId>
<artifactId>hawkbit-mgmt-resource</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ddi-resource</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@@ -87,6 +92,11 @@
<artifactId>hawkbit-http-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring -->
<dependency>
@@ -96,16 +106,26 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Log4j API and Core implementation required for binding -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<!-- Logging binding for java-util-logging e.g. Tomcat -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<!-- Logging binding for Jakarta Commons Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!-- Logging binding for Log4J Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>

View File

@@ -8,13 +8,12 @@
*/
package org.eclipse.hawkbit.app;
import org.eclipse.hawkbit.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.EnableJpaRepository;
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
import org.eclipse.hawkbit.controller.EnableDirectDeviceApi;
import org.eclipse.hawkbit.rest.resource.EnableRestResources;
import org.eclipse.hawkbit.ddi.EnableDdiApi;
import org.eclipse.hawkbit.mgmt.EnableMgmtApi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
/**
* A {@link SpringBootApplication} annotated class with a main method to start.
@@ -22,10 +21,10 @@ import org.springframework.context.annotation.Import;
*
*/
@SpringBootApplication
@Import({ RepositoryApplicationConfiguration.class })
@EnableHawkbitManagedSecurityConfiguration
@EnableRestResources
@EnableDirectDeviceApi
@EnableMgmtApi
@EnableDdiApi
@EnableJpaRepository
// Exception squid:S1118 - Spring boot standard behavior
@SuppressWarnings({ "squid:S1118" })
public class Start {

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit.eventbus.DeadEventListener" level="WARN" />
<Logger name="org.springframework.boot.actuate.audit.listener.AuditListener" level="WARN" />
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN" />
<Logger name="org.apache.tomcat.jdbc.pool.ConnectionPool" level="DEBUG" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR" />
<!-- Security Log with hints on potential attacks -->
<logger name="server-security" level="INFO" />
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</configuration>

View File

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

View File

@@ -0,0 +1,46 @@
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-example-core-feign-client</artifactId>
<name>hawkBit-example :: Feign Core Client</name>
<dependencies>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-core</artifactId>
<version>1.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-slf4j</artifactId>
</dependency>
</dependencies>
</project>

View File

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

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.feign.core.client;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.netflix.feign.FeignClientsConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import feign.Contract;
import feign.Feign;
/**
* Spring annotated java configuration class which defines necessary beans for
* configure the feign-client.
*/
@Configuration
@ConditionalOnClass(Feign.class)
@Import(FeignClientsConfiguration.class)
public class FeignClientConfiguration {
@Bean
public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() {
return new ApplicationJsonRequestHeaderInterceptor();
}
@Bean
public Contract feignContract() {
return new IgnoreMultipleConsumersProducersSpringMvcContract();
}
}

View File

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

View File

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

View File

@@ -0,0 +1,68 @@
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-example-ddi-feign-client</artifactId>
<name>hawkBit-example :: DDI Feign Client</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.0.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-example-core-feign-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ddi-dl-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ddi-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,56 @@
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<artifactId>hawkbit-example-mgmt-feign-client</artifactId>
<name>hawkBit-example :: Management client API</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-example-core-feign-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-mgmt-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<!-- need to overwrite for the interface inheritance feature of feign-core -->
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate</groupId>
</dependency>
</dependencies>
</project>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,135 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment;
import com.google.common.collect.Lists;
/**
* Builder pattern for building {@link MgmtDistributionSetRequestBodyPost}.
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class DistributionSetBuilder {
private String name;
private String version;
private String type;
private String description;
private final List<MgmtSoftwareModuleAssigment> modules = new ArrayList<>();
/**
* @param name
* the name of the distribution set
* @return the builder itself
*/
public DistributionSetBuilder name(final String name) {
this.name = name;
return this;
}
public DistributionSetBuilder moduleByID(final Long id) {
final MgmtSoftwareModuleAssigment softwareModuleAssigmentRest = new MgmtSoftwareModuleAssigment();
softwareModuleAssigmentRest.setId(id);
modules.add(softwareModuleAssigmentRest);
return this;
}
/**
* @param version
* the version of the distribution set
* @return the builder itself
*/
public DistributionSetBuilder version(final String version) {
this.version = version;
return this;
}
/**
* @param type
* the distribution set type name for this distribution set
* @return the builder itself
*/
public DistributionSetBuilder type(final String type) {
this.type = type;
return this;
}
/**
* @param description
* the description
* @return the builder itself
*/
public DistributionSetBuilder description(final String description) {
this.description = description;
return this;
}
/**
* Builds a list with a single entry of
* {@link MgmtDistributionSetRequestBodyPost} which can directly be used to
* post on the RESTful-API.
*
* @return a single entry list of {@link MgmtDistributionSetRequestBodyPost}
*/
public List<MgmtDistributionSetRequestBodyPost> build() {
return Lists.newArrayList(doBuild(""));
}
/**
* Builds a list of multiple {@link MgmtDistributionSetRequestBodyPost} to
* create multiple distribution sets at once. An increasing number will be
* used for version of the distribution set. The name and type will remain
* the same.
*
* @param count
* the amount of distribution sets body which should be created
* @return a list of {@link MgmtDistributionSetRequestBodyPost}
*/
public List<MgmtDistributionSetRequestBodyPost> buildAsList(final int count) {
return buildAsList(0, count);
}
/**
* Builds a list of multiple {@link MgmtDistributionSetRequestBodyPost} to
* create multiple distribution sets at once. An increasing number will be
* used for version of the distribution set starting from given offset. The
* name and type will remain the same.
*
* @param count
* the amount of distribution sets body which should be created
* @param offset
* for for index start
* @return a list of {@link MgmtDistributionSetRequestBodyPost}
*/
public List<MgmtDistributionSetRequestBodyPost> buildAsList(final int offset, final int count) {
final ArrayList<MgmtDistributionSetRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = offset; index < count + offset; index++) {
bodyList.add(doBuild(String.valueOf(index)));
}
return bodyList;
}
private MgmtDistributionSetRequestBodyPost doBuild(final String suffix) {
final MgmtDistributionSetRequestBodyPost body = new MgmtDistributionSetRequestBodyPost();
body.setName(name);
body.setVersion(version + suffix);
body.setType(type);
body.setDescription(description);
body.setModules(modules);
return body;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,125 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link MgmtSoftwareModuleRequestBodyPost}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class SoftwareModuleBuilder {
private String name;
private String version;
private String type;
private String vendor;
private String description;
/**
* @param name
* the name of the software module
* @return the builder itself
*/
public SoftwareModuleBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param version
* the version of the software module
* @return the builder itsefl
*/
public SoftwareModuleBuilder version(final String version) {
this.version = version;
return this;
}
/**
* @param type
* the key of the software module type to be used for this
* software module
* @return the builder itself
*/
public SoftwareModuleBuilder type(final String type) {
this.type = type;
return this;
}
/**
* @param vendor
* the vendor
* @return the builder itself
*/
public SoftwareModuleBuilder vendor(final String vendor) {
this.vendor = vendor;
return this;
}
/**
* @param description
* the description
* @return the builder itself
*/
public SoftwareModuleBuilder description(final String description) {
this.description = description;
return this;
}
/**
* Builds a list with a single entry of
* {@link MgmtSoftwareModuleRequestBodyPost} which can directly be used in
* the RESTful-API.
*
* @return a single entry list of {@link MgmtSoftwareModuleRequestBodyPost}
*/
public List<MgmtSoftwareModuleRequestBodyPost> build() {
return Lists.newArrayList(doBuild(""));
}
/**
* Builds a list of multiple {@link MgmtSoftwareModuleRequestBodyPost} to
* create multiple software module at once. An increasing number will be
* added to the version of the software module. The name and type will
* remain the same.
*
* @param count
* the amount of software module body which should be created
* @return a list of {@link MgmtDistributionSetTypeRequestBodyPost}
*/
public List<MgmtSoftwareModuleRequestBodyPost> buildAsList(final int count) {
final ArrayList<MgmtSoftwareModuleRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(String.valueOf(index)));
}
return bodyList;
}
private MgmtSoftwareModuleRequestBodyPost doBuild(final String suffix) {
final MgmtSoftwareModuleRequestBodyPost body = new MgmtSoftwareModuleRequestBodyPost();
body.setName(name);
body.setVersion(version + suffix);
body.setType(type);
body.setVendor(vendor);
body.setDescription(description);
return body;
}
}

View File

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

View File

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

View File

@@ -0,0 +1,130 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link MgmtTargetRequestBody}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class TargetBuilder {
private String controllerId;
private String name;
private String description;
private String address;
/**
* @param controllerId
* the ID of the controller/target
* @return the builder itself
*/
public TargetBuilder controllerId(final String controllerId) {
this.controllerId = controllerId;
return this;
}
/**
* @param name
* the name of the target
* @return the builder itself
*/
public TargetBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param address
* the address of the target
* @return the builder itself
*/
public TargetBuilder address(final String address) {
this.address = address;
return this;
}
/**
* @param description
* the description of the target
* @return the builder itself
*/
public TargetBuilder description(final String description) {
this.description = description;
return this;
}
/**
* Builds a list with a single entry of {@link MgmtTargetRequestBody} which
* can directly be used in the RESTful-API.
*
* @return a single entry list of {@link MgmtTargetRequestBody}
*/
public List<MgmtTargetRequestBody> build() {
return Lists.newArrayList(doBuild(""));
}
/**
* Builds a list of multiple {@link MgmtTargetRequestBody} to create
* multiple targets at once. An increasing number will be added to the
* controllerId and name of the target. The description will remain.
*
* @param count
* the amount of target bodies which should be created
* @param offset
* for
* @return a list of {@link MgmtSoftwareModuleTypeRequestBodyPost}
*/
public List<MgmtTargetRequestBody> buildAsList(final int count) {
return buildAsList(0, count);
}
/**
* Builds a list of multiple {@link MgmtTargetRequestBody} to create
* multiple targets at once. An increasing number will be added to the
* controllerId and name of the target starting from the provided offset.
* The description will remain.
*
* @param count
* the amount of target bodies which should be created
* @param offset
* for for index start
* @return a list of {@link MgmtSoftwareModuleTypeRequestBodyPost}
*/
public List<MgmtTargetRequestBody> buildAsList(final int offset, final int count) {
final List<MgmtTargetRequestBody> bodyList = Lists.newArrayList();
for (int index = offset; index < count + offset; index++) {
bodyList.add(doBuild(String.valueOf(index)));
}
return bodyList;
}
private MgmtTargetRequestBody doBuild(final String suffix) {
final MgmtTargetRequestBody body = new MgmtTargetRequestBody();
body.setControllerId(controllerId + suffix);
if (name == null) {
name = controllerId;
}
body.setName(name + suffix);
body.setDescription(description);
body.setAddress(address);
return body;
}
}

View File

@@ -0,0 +1,4 @@
/target/
/bin/
/.apt_generated/
/.springBeans

View File

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

View File

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

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client;
import org.eclipse.hawkbit.feign.core.client.FeignClientConfiguration;
import org.eclipse.hawkbit.feign.core.client.IgnoreMultipleConsumersProducersSpringMvcContract;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtRolloutClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtTargetClientResource;
import org.eclipse.hawkbit.mgmt.client.scenarios.ConfigurableScenario;
import org.eclipse.hawkbit.mgmt.client.scenarios.CreateStartedRolloutExample;
import org.eclipse.hawkbit.mgmt.client.scenarios.upload.FeignMultipartEncoder;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.hateoas.hal.Jackson2HalModule;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.Feign;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import feign.jackson.JacksonDecoder;
import feign.slf4j.Slf4jLogger;
@SpringBootApplication
@EnableFeignClients("org.eclipse.hawkbit.mgmt.client.resource")
@EnableConfigurationProperties(ClientConfigurationProperties.class)
@Configuration
@AutoConfigureAfter(FeignClientConfiguration.class)
@Import(FeignClientConfiguration.class)
public class Application implements CommandLineRunner {
@Autowired
private ClientConfigurationProperties configuration;
@Autowired
private ConfigurableScenario configuredScenario;
@Autowired
private CreateStartedRolloutExample gettingStartedRolloutScenario;
public static void main(final String[] args) {
new SpringApplicationBuilder().showBanner(false).sources(Application.class).run(args);
}
@Override
public void run(final String... args) throws Exception {
if (containsArg("--createrollout", args)) {
// run the create and start rollout example
gettingStartedRolloutScenario.run();
} else {
// run the configured scenario from properties
configuredScenario.run();
}
}
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(configuration.getUsername(), configuration.getPassword());
}
@Bean
public ConfigurableScenario configurableScenario(final MgmtDistributionSetClientResource distributionSetResource,
@Qualifier("mgmtSoftwareModuleClientResource") final MgmtSoftwareModuleClientResource softwareModuleResource,
@Qualifier("uploadSoftwareModule") final MgmtSoftwareModuleClientResource uploadSoftwareModule,
final MgmtTargetClientResource targetResource, final MgmtRolloutClientResource rolloutResource,
final ClientConfigurationProperties clientConfigurationProperties) {
return new ConfigurableScenario(distributionSetResource, softwareModuleResource, uploadSoftwareModule,
targetResource, rolloutResource, clientConfigurationProperties);
}
@Bean
public CreateStartedRolloutExample createStartedRolloutExample() {
return new CreateStartedRolloutExample();
}
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
public MgmtSoftwareModuleClientResource uploadSoftwareModule() {
final ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(new Jackson2HalModule());
return Feign.builder().contract(new IgnoreMultipleConsumersProducersSpringMvcContract())
.requestInterceptor(
new BasicAuthRequestInterceptor(configuration.getUsername(), configuration.getPassword()))
.logger(new Slf4jLogger()).encoder(new FeignMultipartEncoder())
.decoder(new ResponseEntityDecoder(new JacksonDecoder(mapper)))
.target(MgmtSoftwareModuleClientResource.class,
configuration.getUrl() + MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING);
}
private static boolean containsArg(final String containsArg, final String... args) {
for (final String arg : args) {
if (arg.equalsIgnoreCase(containsArg)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,199 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration bean which holds the configuration of the client e.g. the base
* URL of the hawkbit-server and the credentials to use the RESTful Management
* API.
*/
@ConfigurationProperties(prefix = "hawkbit")
public class ClientConfigurationProperties {
/**
* Update server URI.
*/
private String url = "localhost:8080";
/**
* Update server user name.
*/
private String username = "admin";
/**
* Update server password.
*/
private String password = "admin"; // NOSONAR this password is only used for
// examples
private final List<Scenario> scenarios = new ArrayList<>();
/**
* Simulation {@link Scenario}.
*
*/
public static class Scenario {
private boolean cleanRepository;
private int targets = 100;
private int distributionSets = 10;
private int appModulesPerDistributionSet = 2;
private String dsName = "Package";
private String smSwName = "Application";
private String smFwName = "Firmware";
private String targetName = "Device";
private int artifactsPerSM = 1;
private String targetAddress = "amqp:/simulator.replyTo";
private boolean runRollouts = true;
private int rolloutDeploymentGroups = 4;
/**
* Artifact size. Values can use the suffixed "MB" or "KB" to indicate a
* Megabyte or Kilobyte size.
*/
private String artifactSize = "1MB";
public boolean isCleanRepository() {
return cleanRepository;
}
public void setCleanRepository(final boolean cleanRepository) {
this.cleanRepository = cleanRepository;
}
public int getRolloutDeploymentGroups() {
return rolloutDeploymentGroups;
}
public void setRolloutDeploymentGroups(final int rolloutDeploymentGroups) {
this.rolloutDeploymentGroups = rolloutDeploymentGroups;
}
public boolean isRunRollouts() {
return runRollouts;
}
public void setRunRollouts(final boolean runRollouts) {
this.runRollouts = runRollouts;
}
public String getTargetAddress() {
return targetAddress;
}
public void setTargetAddress(final String targetAddress) {
this.targetAddress = targetAddress;
}
public int getArtifactsPerSM() {
return artifactsPerSM;
}
public void setArtifactsPerSM(final int artifactsPerSM) {
this.artifactsPerSM = artifactsPerSM;
}
public String getArtifactSize() {
return artifactSize;
}
public void setArtifactSize(final String artifactSize) {
this.artifactSize = artifactSize;
}
public String getTargetName() {
return targetName;
}
public void setTargetName(final String targetName) {
this.targetName = targetName;
}
public String getDsName() {
return dsName;
}
public void setDsName(final String dsName) {
this.dsName = dsName;
}
public String getSmSwName() {
return smSwName;
}
public void setSmSwName(final String smSwName) {
this.smSwName = smSwName;
}
public String getSmFwName() {
return smFwName;
}
public void setSmFwName(final String smFwName) {
this.smFwName = smFwName;
}
public int getTargets() {
return targets;
}
public int getDistributionSets() {
return distributionSets;
}
public int getAppModulesPerDistributionSet() {
return appModulesPerDistributionSet;
}
public void setTargets(final int targets) {
this.targets = targets;
}
public void setDistributionSets(final int distributionSets) {
this.distributionSets = distributionSets;
}
public void setAppModulesPerDistributionSet(final int appModulesPerDistributionSet) {
this.appModulesPerDistributionSet = appModulesPerDistributionSet;
}
}
public List<Scenario> getScenarios() {
return scenarios;
}
public String getUrl() {
return url;
}
public void setUrl(final String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
}

View File

@@ -0,0 +1,242 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.scenarios;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.mgmt.client.ClientConfigurationProperties;
import org.eclipse.hawkbit.mgmt.client.ClientConfigurationProperties.Scenario;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtDistributionSetClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtRolloutClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtSoftwareModuleClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.MgmtTargetClientResource;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.RolloutBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.TargetBuilder;
import org.eclipse.hawkbit.mgmt.client.scenarios.upload.ArtifactFile;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
/**
*
* A configurable scenario which runs the configured scenarios.
*
* @see {@link ClientConfigurationProperties#getScenarios()}
*
*/
public class ConfigurableScenario {
private static final int PAGE_SIZE = 100;
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurableScenario.class);
private final MgmtDistributionSetClientResource distributionSetResource;
private final MgmtSoftwareModuleClientResource softwareModuleResource;
private final MgmtSoftwareModuleClientResource uploadSoftwareModule;
private final MgmtTargetClientResource targetResource;
private final MgmtRolloutClientResource rolloutResource;
private final ClientConfigurationProperties clientConfigurationProperties;
public ConfigurableScenario(final MgmtDistributionSetClientResource distributionSetResource,
@Qualifier("mgmtSoftwareModuleClientResource") final MgmtSoftwareModuleClientResource softwareModuleResource,
@Qualifier("uploadSoftwareModule") final MgmtSoftwareModuleClientResource uploadSoftwareModule,
final MgmtTargetClientResource targetResource, final MgmtRolloutClientResource rolloutResource,
final ClientConfigurationProperties clientConfigurationProperties) {
this.distributionSetResource = distributionSetResource;
this.softwareModuleResource = softwareModuleResource;
this.uploadSoftwareModule = uploadSoftwareModule;
this.targetResource = targetResource;
this.rolloutResource = rolloutResource;
this.clientConfigurationProperties = clientConfigurationProperties;
}
/**
* Run the default getting started scenario.
*/
public void run() {
LOGGER.info("Running Configurable Scenario...");
clientConfigurationProperties.getScenarios().forEach(this::createScenario);
}
private void createScenario(final Scenario scenario) {
if (scenario.isCleanRepository()) {
cleanRepository();
}
createTargets(scenario);
createDistributionSets(scenario);
if (scenario.isRunRollouts()) {
runRollouts(scenario);
}
}
private void cleanRepository() {
LOGGER.info("Cleaning repository");
deleteTargets();
deleteRollouts();
deleteDistributionSets();
deleteSoftwareModules();
LOGGER.info("Cleaning repository -> Done");
}
private void deleteRollouts() {
// TODO: complete this as soon as rollouts can be deleted
}
private void deleteSoftwareModules() {
PagedList<MgmtSoftwareModule> modules;
do {
modules = softwareModuleResource.getSoftwareModules(0, PAGE_SIZE, null, null).getBody();
modules.getContent().forEach(module -> softwareModuleResource.deleteSoftwareModule(module.getModuleId()));
} while (modules.getTotal() > PAGE_SIZE);
}
private void deleteDistributionSets() {
PagedList<MgmtDistributionSet> distributionSets;
do {
distributionSets = distributionSetResource.getDistributionSets(0, PAGE_SIZE, null, null).getBody();
distributionSets.getContent().forEach(set -> distributionSetResource.deleteDistributionSet(set.getDsId()));
} while (distributionSets.getTotal() > PAGE_SIZE);
}
private void deleteTargets() {
PagedList<MgmtTarget> targets;
do {
targets = targetResource.getTargets(0, PAGE_SIZE, null, null).getBody();
targets.getContent().forEach(target -> targetResource.deleteTarget(target.getControllerId()));
} while (targets.getTotal() > PAGE_SIZE);
}
private void runRollouts(final Scenario scenario) {
distributionSetResource.getDistributionSets(0, scenario.getDistributionSets(), null, null).getBody()
.getContent().forEach(set -> runRollout(set, scenario));
}
private void runRollout(final MgmtDistributionSet set, final Scenario scenario) {
LOGGER.info("Run rollout for set {}", set.getDsId());
// create a Rollout
final MgmtRolloutResponseBody rolloutResponseBody = rolloutResource
.create(new RolloutBuilder().name("Rollout" + set.getName() + set.getVersion())
.groupSize(scenario.getRolloutDeploymentGroups()).targetFilterQuery("name==*")
.distributionSetId(set.getDsId()).successThreshold("80").errorThreshold("5").build())
.getBody();
// start the created Rollout
rolloutResource.start(rolloutResponseBody.getRolloutId(), true);
// wait until rollout is complete
do {
try {
TimeUnit.SECONDS.sleep(35);
} catch (final InterruptedException e) {
LOGGER.warn("Interrupted!");
Thread.currentThread().interrupt();
}
} while (targetResource.getTargets(0, 1, null, "updateStatus==IN_SYNC").getBody().getTotal() < scenario
.getTargets());
LOGGER.info("Run rollout for set {} -> Done", set.getDsId());
}
private void createDistributionSets(final Scenario scenario) {
LOGGER.info("Creating {} distribution sets", scenario.getDistributionSets());
final byte[] artifact = generateArtifact(scenario);
distributionSetResource.createDistributionSets(new DistributionSetBuilder().name(scenario.getDsName())
.type("os_app").version("1.0.").buildAsList(scenario.getDistributionSets())).getBody()
.forEach(dsSet -> {
final List<MgmtSoftwareModule> modules = addModules(scenario, dsSet, artifact);
final SoftwareModuleAssigmentBuilder assign = new SoftwareModuleAssigmentBuilder();
modules.forEach(module -> assign.id(module.getModuleId()));
distributionSetResource.assignSoftwareModules(dsSet.getDsId(), assign.build());
});
LOGGER.info("Creating {} distribution sets -> Done", scenario.getDistributionSets());
}
private List<MgmtSoftwareModule> addModules(final Scenario scenario, final MgmtDistributionSet dsSet,
final byte[] artifact) {
final List<MgmtSoftwareModule> modules = softwareModuleResource
.createSoftwareModules(new SoftwareModuleBuilder().name(scenario.getSmFwName() + "-os")
.version(dsSet.getVersion()).type("os").build())
.getBody();
modules.addAll(softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(scenario.getSmSwName() + "-app").version(dsSet.getVersion() + ".")
.type("application").buildAsList(scenario.getAppModulesPerDistributionSet()))
.getBody());
for (int x = 0; x < scenario.getArtifactsPerSM(); x++) {
modules.forEach(module -> {
final ArtifactFile file = new ArtifactFile("dummyfile.dummy", null, "multipart/form-data", artifact);
uploadSoftwareModule.uploadArtifact(module.getModuleId(), file, null, null, null);
});
}
return modules;
}
private static byte[] generateArtifact(final Scenario scenario) {
// Exception squid:S2245 - not used for cryptographic function
@SuppressWarnings("squid:S2245")
final Random random = new Random();
// create byte array
final byte[] nbyte = new byte[parseSize(scenario.getArtifactSize())];
// put the next byte in the array
random.nextBytes(nbyte);
return nbyte;
}
private void createTargets(final Scenario scenario) {
LOGGER.info("Creating {} targets", scenario.getTargets());
for (int i = 0; i < (scenario.getTargets() / PAGE_SIZE); i++) {
targetResource.createTargets(
new TargetBuilder().controllerId(scenario.getTargetName()).address(scenario.getTargetAddress())
.buildAsList(i * PAGE_SIZE, (i + 1) * PAGE_SIZE > scenario.getTargets()
? (scenario.getTargets() - (i * PAGE_SIZE)) : PAGE_SIZE));
}
LOGGER.info("Creating {} targets -> Done", scenario.getTargets());
}
private static int parseSize(final String s) {
final String size = s.toUpperCase();
if (size.endsWith("KB")) {
return Integer.valueOf(size.substring(0, size.length() - 2)) * 1024;
}
if (size.endsWith("MB")) {
return Integer.valueOf(size.substring(0, size.length() - 2)) * 1024 * 1024;
}
return Integer.valueOf(size);
}
}

View File

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

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.scenarios.upload;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
/**
* Implementation for {@link MultipartFile} for hawkBit artifact upload.
*
*/
public class ArtifactFile implements MultipartFile {
private final String name;
private final String originalFilename;
private final String contentType;
private final byte[] content;
/**
* Create a new ArtifactFile with the given content.
*
* @param name
* the name of the file
* @param content
* the content of the file
*/
public ArtifactFile(final String name, final byte[] content) {
this(name, "", null, content);
}
/**
* Create a new ArtifactFile with the given content.
*
* @param name
* of the file
* @param originalFilename
* the original filename (as on the client's machine)
* @param contentType
* the content type
* @param content
* of the file
*/
public ArtifactFile(final String name, final String originalFilename, final String contentType,
final byte[] content) {
Assert.hasLength(name, "Name must not be null");
this.name = name;
this.originalFilename = Optional.ofNullable(originalFilename).orElse("");
this.contentType = contentType;
this.content = Optional.ofNullable(content).orElse(new byte[0]);
}
@Override
public String getName() {
return this.name;
}
@Override
public String getOriginalFilename() {
return this.originalFilename;
}
@Override
public String getContentType() {
return this.contentType;
}
@Override
public boolean isEmpty() {
return this.content.length == 0;
}
@Override
public long getSize() {
return this.content.length;
}
@Override
public byte[] getBytes() throws IOException {
return this.content;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(this.content);
}
@Override
public void transferTo(final File dest) throws IOException {
FileCopyUtils.copy(this.content, dest);
}
}

View File

@@ -0,0 +1,155 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.scenarios.upload;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map.Entry;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
/**
* A feign encoder implementation which handles {@link MultipartFile} body.
*/
public class FeignMultipartEncoder implements Encoder {
private final List<HttpMessageConverter<?>> converters = new RestTemplate().getMessageConverters();
private final HttpHeaders multipartHeaders = new HttpHeaders();
private final HttpHeaders jsonHeaders = new HttpHeaders();
private static final Charset UTF_8 = Charset.forName("UTF-8");
public FeignMultipartEncoder() {
multipartHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
jsonHeaders.setContentType(MediaType.APPLICATION_JSON);
}
@Override
public void encode(final Object object, final Type bodyType, final RequestTemplate template) {
encodeMultipartFormRequest(object, template);
}
private void encodeMultipartFormRequest(final Object value, final RequestTemplate template) {
if (value == null) {
throw new EncodeException("Cannot encode request with null value.");
}
if (!isMultipartFile(value)) {
throw new EncodeException("Only multipart can be handled by this encoder");
}
encodeRequest(encodeMultipartFile((MultipartFile) value), multipartHeaders, template);
}
@SuppressWarnings("unchecked")
private void encodeRequest(final Object value, final HttpHeaders requestHeaders, final RequestTemplate template) {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final HttpOutputMessage dummyRequest = new HttpOutputMessageImpl(outputStream, requestHeaders);
try {
final Class<?> requestType = value.getClass();
final MediaType requestContentType = requestHeaders.getContentType();
for (final HttpMessageConverter<?> messageConverter : converters) {
if (messageConverter.canWrite(requestType, requestContentType)) {
((HttpMessageConverter<Object>) messageConverter).write(value, requestContentType, dummyRequest);
break;
}
}
} catch (final IOException ex) {
throw new EncodeException("Cannot encode request.", ex);
}
final HttpHeaders headers = dummyRequest.getHeaders();
if (headers != null) {
for (final Entry<String, List<String>> entry : headers.entrySet()) {
template.header(entry.getKey(), entry.getValue());
}
}
/*
* we should use a template output stream... this will cause issues if
* files are too big, since the whole request will be in memory.
*/
template.body(outputStream.toByteArray(), UTF_8);
}
private MultiValueMap<String, Object> encodeMultipartFile(final MultipartFile file) {
try {
final MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
multiValueMap.add("file", new MultipartFileResource(file.getName(), file.getSize(), file.getInputStream()));
return multiValueMap;
} catch (final IOException ex) {
throw new EncodeException("Cannot encode request.", ex);
}
}
private static boolean isMultipartFile(final Object object) {
return object instanceof MultipartFile;
}
private static final class HttpOutputMessageImpl implements HttpOutputMessage {
private final OutputStream body;
private final HttpHeaders headers;
private HttpOutputMessageImpl(final OutputStream body, final HttpHeaders headers) {
this.body = body;
this.headers = headers;
}
@Override
public OutputStream getBody() throws IOException {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}
/**
* Dummy resource class. Wraps file content and its original name.
*/
static class MultipartFileResource extends InputStreamResource {
private final String filename;
private final long size;
public MultipartFileResource(final String filename, final long size, final InputStream inputStream) {
super(inputStream);
this.size = size;
this.filename = filename;
}
@Override
public String getFilename() {
return this.filename;
}
@Override
public long contentLength() throws IOException {
return size;
}
}
}

View File

@@ -0,0 +1,22 @@
#
# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
hawkbit.url=http://localhost:8080
hawkbit.username=admin
hawkbit.password=admin
spring.main.show-banner=false
hawkbit.scenarios.[0].cleanRepository=false
hawkbit.scenarios.[0].targets=0
hawkbit.scenarios.[0].ds-name=gettingstarted-example
hawkbit.scenarios.[0].distribution-sets=3
hawkbit.scenarios.[0].sm-fw-name=gettingstarted-example
hawkbit.scenarios.[0].sm-sw-name=gettingstarted-example
hawkbit.scenarios.[0].runRollouts=false

View File

@@ -10,17 +10,11 @@
-->
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- Log message format -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit" level="info" />
<logger name="feign.Logger" level="debug" />
<root level="error">
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>

View File

@@ -1,77 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client;
import org.eclipse.hawkbit.mgmt.client.scenarios.CreateStartedRolloutExample;
import org.eclipse.hawkbit.mgmt.client.scenarios.GettingStartedDefaultScenario;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import feign.Contract;
import feign.auth.BasicAuthRequestInterceptor;
@SpringBootApplication
@EnableFeignClients
@EnableConfigurationProperties(ClientConfigurationProperties.class)
public class Application implements CommandLineRunner {
@Autowired
private ClientConfigurationProperties configuration;
@Autowired
private GettingStartedDefaultScenario gettingStarted;
@Autowired
private CreateStartedRolloutExample gettingStartedRolloutScenario;
public static void main(final String[] args) {
new SpringApplicationBuilder().showBanner(false).sources(Application.class).run(args);
}
@Override
public void run(final String... args) throws Exception {
if (containsArg("--createrollout", args)) {
// run the create and start rollout example
gettingStartedRolloutScenario.run();
} else {
// run the getting started scenario which creates a setup of
// distribution set and software modules to be used
gettingStarted.run();
}
}
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(configuration.getUsername(), configuration.getPassword());
}
@Bean
public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() {
return new ApplicationJsonRequestHeaderInterceptor();
}
@Bean
public Contract feignContract() {
return new IgnoreMultipleConsumersProducersSpringMvcContract();
}
private boolean containsArg(final String containsArg, final String... args) {
for (final String arg : args) {
if (arg.equalsIgnoreCase(containsArg)) {
return true;
}
}
return false;
}
}

View File

@@ -1,60 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration bean which holds the configuration of the client e.g. the base
* URL of the hawkbit-server and the credentials to use the RESTful Management
* API.
*/
@ConfigurationProperties(prefix = "hawkbit")
public class ClientConfigurationProperties {
/**
* Update server URI.
*/
private String url = "localhost:8080";
/**
* Update server user name.
*/
private String username = "admin";
/**
* Update server password.
*/
private String password = "admin"; // NOSONAR this password is only used for
// examples
public String getUrl() {
return url;
}
public void setUrl(final String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
}

View File

@@ -1,96 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRequestBodyPost;
import com.google.common.collect.Lists;
/**
* Builder pattern for building {@link DistributionSetRequestBodyPost}.
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class DistributionSetBuilder {
private String name;
private String version;
private String type;
/**
* @param name
* the name of the distribution set
* @return the builder itself
*/
public DistributionSetBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param version
* the version of the distribution set
* @return the builder itself
*/
public DistributionSetBuilder version(final String version) {
this.version = version;
return this;
}
/**
* @param type
* the distribution set type name for this distribution set
* @return the builder itself
*/
public DistributionSetBuilder type(final String type) {
this.type = type;
return this;
}
/**
* Builds a list with a single entry of
* {@link DistributionSetRequestBodyPost} which can directly be used to post
* on the RESTful-API.
*
* @return a single entry list of {@link DistributionSetRequestBodyPost}
*/
public List<DistributionSetRequestBodyPost> build() {
return Lists.newArrayList(doBuild(name));
}
/**
* Builds a list of multiple {@link DistributionSetRequestBodyPost} to
* create multiple distribution sets at once. An increasing number will be
* added to the name of the distribution set. The version and type will
* remain the same.
*
* @param count
* the amount of distribution sets body which should be created
* @return a list of {@link DistributionSetRequestBodyPost}
*/
public List<DistributionSetRequestBodyPost> buildAsList(final int count) {
final ArrayList<DistributionSetRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index));
}
return bodyList;
}
private DistributionSetRequestBodyPost doBuild(final String prefixName) {
final DistributionSetRequestBodyPost body = new DistributionSetRequestBodyPost();
body.setName(prefixName);
body.setVersion(version);
body.setType(type);
return body;
}
}

View File

@@ -1,101 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.distributionsettype.DistributionSetTypeRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRequestBodyPost;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link SoftwareModuleRequestBodyPost}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class SoftwareModuleBuilder {
private String name;
private String version;
private String type;
/**
* @param name
* the name of the software module
* @return the builder itself
*/
public SoftwareModuleBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param version
* the version of the software module
* @return the builder itsefl
*/
public SoftwareModuleBuilder version(final String version) {
this.version = version;
return this;
}
/**
* @param type
* the key of the software module type to be used for this
* software module
* @return the builder itself
*/
public SoftwareModuleBuilder type(final String type) {
this.type = type;
return this;
}
/**
* Builds a list with a single entry of
* {@link SoftwareModuleRequestBodyPost} which can directly be used in the
* RESTful-API.
*
* @return a single entry list of {@link SoftwareModuleRequestBodyPost}
*/
public List<SoftwareModuleRequestBodyPost> build() {
return Lists.newArrayList(doBuild(name));
}
/**
* Builds a list of multiple {@link SoftwareModuleRequestBodyPost} to create
* multiple software module at once. An increasing number will be added to
* the name of the software module. The version and type will remain the
* same.
*
* @param count
* the amount of software module body which should be created
* @return a list of {@link DistributionSetTypeRequestBodyPost}
*/
public List<SoftwareModuleRequestBodyPost> buildAsList(final int count) {
final ArrayList<SoftwareModuleRequestBodyPost> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(name + index));
}
return bodyList;
}
private SoftwareModuleRequestBodyPost doBuild(final String prefixName) {
final SoftwareModuleRequestBodyPost body = new SoftwareModuleRequestBodyPost();
body.setName(prefixName);
body.setVersion(version);
body.setType(type);
return body;
}
}

View File

@@ -1,98 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.resource.builder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRequestBodyPost;
import org.eclipse.hawkbit.rest.resource.model.target.TargetRequestBody;
import com.google.common.collect.Lists;
/**
*
* Builder pattern for building {@link TargetRequestBody}.
*
*/
// Exception squid:S1701 - builder pattern
@SuppressWarnings({ "squid:S1701" })
public class TargetBuilder {
private String controllerId;
private String name;
private String description;
/**
* @param controllerId
* the ID of the controller/target
* @return the builder itself
*/
public TargetBuilder controllerId(final String controllerId) {
this.controllerId = controllerId;
return this;
}
/**
* @param name
* the name of the target
* @return the builder itself
*/
public TargetBuilder name(final String name) {
this.name = name;
return this;
}
/**
* @param description
* the description of the target
* @return the builder itself
*/
public TargetBuilder description(final String description) {
this.description = description;
return this;
}
/**
* Builds a list with a single entry of {@link TargetRequestBody} which can
* directly be used in the RESTful-API.
*
* @return a single entry list of {@link TargetRequestBody}
*/
public List<TargetRequestBody> build() {
return Lists.newArrayList(doBuild(controllerId));
}
/**
* Builds a list of multiple {@link TargetRequestBody} to create multiple
* targets at once. An increasing number will be added to the controllerId
* of the target. The name and description will remain.
*
* @param count
* the amount of software module type bodies which should be
* created
* @return a list of {@link SoftwareModuleTypeRequestBodyPost}
*/
public List<TargetRequestBody> buildAsList(final int count) {
final ArrayList<TargetRequestBody> bodyList = Lists.newArrayList();
for (int index = 0; index < count; index++) {
bodyList.add(doBuild(controllerId + index));
}
return bodyList;
}
private TargetRequestBody doBuild(final String prefixControllerId) {
final TargetRequestBody body = new TargetRequestBody();
body.setControllerId(prefixControllerId);
body.setName(name);
body.setDescription(description);
return body;
}
}

View File

@@ -1,137 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.client.scenarios;
import java.util.List;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.DistributionSetTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.SoftwareModuleTypeResourceClient;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.DistributionSetTypeBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleAssigmentBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleBuilder;
import org.eclipse.hawkbit.mgmt.client.resource.builder.SoftwareModuleTypeBuilder;
import org.eclipse.hawkbit.rest.resource.model.distributionset.DistributionSetRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremodule.SoftwareModuleRest;
import org.eclipse.hawkbit.rest.resource.model.softwaremoduletype.SoftwareModuleTypeRest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
*
* Default getting started scenario.
*
*/
@Component
public class GettingStartedDefaultScenario {
private static final Logger LOGGER = LoggerFactory.getLogger(GettingStartedDefaultScenario.class);
/* known software module type name and key */
private static final String SM_MODULE_TYPE = "gettingstarted";
/* known distribution set type name and key */
private static final String DS_MODULE_TYPE = SM_MODULE_TYPE;
/* known distribution name of this getting started example */
private static final String SM_EXAMPLE_NAME = "gettingstarted-example";
/* known distribution name of this getting started example */
private static final String DS_EXAMPLE_NAME = SM_EXAMPLE_NAME;
@Autowired
private DistributionSetResourceClient distributionSetResource;
@Autowired
private DistributionSetTypeResourceClient distributionSetTypeResource;
@Autowired
private SoftwareModuleResourceClient softwareModuleResource;
@Autowired
private SoftwareModuleTypeResourceClient softwareModuleTypeResource;
/**
* Run the default getting started scenario.
*/
public void run() {
LOGGER.info("Running Getting-Started-Scenario...");
// create one SoftwareModuleTypes
LOGGER.info("Creating software module type {}", SM_MODULE_TYPE);
final List<SoftwareModuleTypeRest> createdSoftwareModuleTypes = softwareModuleTypeResource
.createSoftwareModuleTypes(new SoftwareModuleTypeBuilder().key(SM_MODULE_TYPE).name(SM_MODULE_TYPE)
.maxAssignments(1).build())
.getBody();
// create one DistributionSetType
LOGGER.info("Creating distribution set type {}", DS_MODULE_TYPE);
distributionSetTypeResource.createDistributionSetTypes(new DistributionSetTypeBuilder().key(DS_MODULE_TYPE)
.name(DS_MODULE_TYPE).mandatorymodules(createdSoftwareModuleTypes.get(0).getModuleId()).build());
// create three DistributionSet
final String dsVersion1 = "1.0.0";
final String dsVersion2 = "2.0.0";
final String dsVersion3 = "2.1.0";
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion1);
final List<DistributionSetRest> distributionSetsRest1 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion1).type(DS_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion2);
final List<DistributionSetRest> distributionSetsRest2 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion2).type(DS_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", DS_EXAMPLE_NAME, dsVersion3);
final List<DistributionSetRest> distributionSetsRest3 = distributionSetResource.createDistributionSets(
new DistributionSetBuilder().name(DS_EXAMPLE_NAME).version(dsVersion3).type(DS_MODULE_TYPE).build())
.getBody();
// create three SoftwareModules
final String swVersion1 = "1";
final String swVersion2 = "2";
final String swVersion3 = "3";
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion1);
final List<SoftwareModuleRest> softwareModulesRest1 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion1).type(SM_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion2);
final List<SoftwareModuleRest> softwareModulesRest2 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion2).type(SM_MODULE_TYPE).build())
.getBody();
LOGGER.info("Creating distribution set {}:{}", SM_EXAMPLE_NAME, swVersion3);
final List<SoftwareModuleRest> softwareModulesRest3 = softwareModuleResource.createSoftwareModules(
new SoftwareModuleBuilder().name(SM_EXAMPLE_NAME).version(swVersion3).type(SM_MODULE_TYPE).build())
.getBody();
// Assign SoftwareModules to DistributionSet
LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion1,
DS_EXAMPLE_NAME, dsVersion1);
distributionSetResource.assignSoftwareModules(distributionSetsRest1.get(0).getDsId(),
new SoftwareModuleAssigmentBuilder().id(softwareModulesRest1.get(0).getModuleId()).build());
LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion2,
DS_EXAMPLE_NAME, dsVersion2);
distributionSetResource.assignSoftwareModules(distributionSetsRest2.get(0).getDsId(),
new SoftwareModuleAssigmentBuilder().id(softwareModulesRest2.get(0).getModuleId()).build());
LOGGER.info("Assign software module {}:{} to distribution set {}:{}", SM_EXAMPLE_NAME, swVersion3,
DS_EXAMPLE_NAME, dsVersion3);
distributionSetResource.assignSoftwareModules(distributionSetsRest3.get(0).getDsId(),
new SoftwareModuleAssigmentBuilder().id(softwareModulesRest3.get(0).getModuleId()).build());
}
}

View File

@@ -1,14 +0,0 @@
#
# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
hawkbit.url=localhost:8080
hawkbit.username=admin
hawkbit.password=admin
spring.main.show-banner=false

View File

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

View File

@@ -87,9 +87,7 @@ public class ArtifactStore implements ArtifactRepository {
/**
* 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.
@@ -100,9 +98,7 @@ public class ArtifactStore implements ArtifactRepository {
/**
* 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.
@@ -124,11 +120,9 @@ public class ArtifactStore implements ArtifactRepository {
try {
LOGGER.debug("storing file {} of content {}", filename, contentType);
tempFile = File.createTempFile("uploadFile", null);
try (final FileOutputStream os = new FileOutputStream(tempFile)) {
try (BufferedOutputStream bos = new BufferedOutputStream(os)) {
try (BufferedInputStream bis = new BufferedInputStream(content)) {
return store(content, contentType, bos, tempFile, hash);
}
try (final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempFile))) {
try (BufferedInputStream bis = new BufferedInputStream(content)) {
return store(bis, contentType, bos, tempFile, hash);
}
}
} catch (final IOException | MongoException e1) {
@@ -207,6 +201,9 @@ public class ArtifactStore implements ArtifactRepository {
throws NoSuchAlgorithmException, IOException {
String sha1Hash;
// compute digest
// Exception squid:S2070 - not used for hashing sensitive
// data
@SuppressWarnings("squid:S2070")
final MessageDigest md = MessageDigest.getInstance("SHA-1");
try (final DigestOutputStream dos = new DigestOutputStream(os, md)) {
ByteStreams.copy(stream, dos);
@@ -230,15 +227,13 @@ public class ArtifactStore implements ArtifactRepository {
* @return a paged list of artifacts mapped from the given dbFiles
*/
private List<DbArtifact> map(final List<GridFSDBFile> dbFiles) {
return dbFiles.stream().map(dbFile -> map(dbFile)).collect(Collectors.toList());
return dbFiles.stream().map(this::map).collect(Collectors.toList());
}
/**
* 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 artifacts
@@ -251,8 +246,6 @@ public class ArtifactStore implements ArtifactRepository {
/**
* 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

View File

@@ -10,18 +10,13 @@ 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 {

View File

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

View File

@@ -25,6 +25,7 @@ import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.SimpleCacheResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* A configuration for configuring the spring {@link CacheManager} for specific
@@ -33,9 +34,6 @@ import org.springframework.context.annotation.Configuration;
*
* This is done by providing a special {@link TenantCacheResolver} which
* generates a cache name included the current tenant.
*
*
*
*/
@Configuration
@EnableCaching
@@ -51,18 +49,27 @@ public class CacheAutoConfiguration extends CachingConfigurerSupport {
@Override
@Bean
@ConditionalOnMissingBean
@Primary
public TenancyCacheManager cacheManager() {
return new TenantAwareCacheManager(new GuavaCacheManager(), tenantAware);
return new TenantAwareCacheManager(directCacheManager(), tenantAware);
}
/**
* @return the direct cache manager to access without tenant aware check,
* cause in sometimes it's necessary to access the cache directly
* without having the current tenant, e.g. initial creation of
* tenant
*/
@Bean(name = "directCacheManager")
@ConditionalOnMissingBean(name = "directCacheManager")
public CacheManager directCacheManager() {
return new GuavaCacheManager();
}
/**
* A {@link SimpleCacheResolver} implementation which includes the
* {@link TenantAware#getCurrentTenant()} into the cache name before
* resolving it.
*
*
*
*
*/
public class TenantCacheResolver extends SimpleCacheResolver {

View File

@@ -31,7 +31,7 @@ public class DownloadIdCacheAutoConfiguration {
private CacheManager cacheManager;
/**
* Bean for the downlod id cache.
* Bean for the download id cache.
*
* @return the cache
*/

View File

@@ -12,7 +12,7 @@ import java.util.concurrent.Executor;
import org.eclipse.hawkbit.eventbus.EventBusSubscriberProcessor;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.repository.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;

View File

@@ -0,0 +1,25 @@
/**
* 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.repository;
import org.eclipse.hawkbit.EnableJpaRepository;
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({ EnableJpaRepository.class })
@Import({ EnableJpaRepository.class })
public class JpaRepositoryAutoConfiguration {
}

View File

@@ -23,7 +23,6 @@ import org.springframework.scheduling.annotation.EnableAsync;
*
*
*/
@Configuration
@EnableAsync
@ConditionalOnMissingBean(AsyncConfigurer.class)

View File

@@ -20,7 +20,7 @@ public class AsyncConfigurerThreadpoolProperties {
/**
* Max queue size for central event executor.
*/
private Integer queuesize = 250;
private Integer queuesize = 5_000;
/**
* Core processing threads for central event executor.
@@ -30,7 +30,12 @@ public class AsyncConfigurerThreadpoolProperties {
/**
* Maximum thread pool size for central event executor.
*/
private Integer maxthreads = 50;
private Integer maxthreads = 20;
/**
* Core processing threads for scheduled event executor.
*/
private Integer schedulerThreads = 3;
/**
* When the number of threads is greater than the core, this is the maximum
@@ -70,4 +75,12 @@ public class AsyncConfigurerThreadpoolProperties {
this.idletimeout = idletimeout;
}
public Integer getSchedulerThreads() {
return schedulerThreads;
}
public void setSchedulerThreads(final Integer schedulerThreads) {
this.schedulerThreads = schedulerThreads;
}
}

View File

@@ -11,7 +11,11 @@ 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.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
@@ -21,7 +25,13 @@ 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.core.task.TaskExecutor;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutor;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
import org.springframework.security.concurrent.DelegatingSecurityContextScheduledExecutorService;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
@@ -39,21 +49,46 @@ public class ExecutorAutoConfiguration {
private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties;
/**
* @return ExecutorService for general purpose multi threaded operations
* @return ExecutorService with security context availability in thread
* execution.
*/
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean
public ExecutorService asyncExecutor() {
return new DelegatingSecurityContextExecutorService(threadPoolExecutor());
}
/**
* @return {@link TaskExecutor} for task execution
*/
@Bean
@ConditionalOnMissingBean
public Executor asyncExecutor() {
public TaskExecutor taskExecutor() {
return new ConcurrentTaskExecutor(asyncExecutor());
}
/**
* @return central ThreadPoolExecutor for general purpose multi threaded
* operations. Tries an orderly shutdown when destroyed.
*/
private ThreadPoolExecutor threadPoolExecutor() {
final BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(
asyncConfigurerProperties.getQueuesize());
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(),
return new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(),
asyncConfigurerProperties.getMaxthreads(), asyncConfigurerProperties.getIdletimeout(),
TimeUnit.MILLISECONDS, blockingQueue,
new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build());
threadPoolExecutor.setRejectedExecutionHandler((r, executor) -> LOGGER.warn(
"Reject runnable for centralExecutorService, reached limit of queue size {}",
executor.getQueue().size()));
return new DelegatingSecurityContextExecutor(threadPoolExecutor);
new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build(),
new PoolSizeExceededPolicy());
}
private static class PoolSizeExceededPolicy extends CallerRunsPolicy {
@Override
public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
LOGGER.warn(
"Caller has to run on its own instead of centralExecutorService, reached limit of queue size {}",
executor.getQueue().size());
super.rejectedExecution(r, executor);
}
}
/**
@@ -69,4 +104,25 @@ public class ExecutorAutoConfiguration {
return new DelegatingSecurityContextExecutor(threadPoolExecutor);
}
/**
* @return {@link ScheduledExecutorService} with security context
* availability in thread execution.
*/
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean
public ScheduledExecutorService scheduledExecutorService() {
return new DelegatingSecurityContextScheduledExecutorService(
Executors.newScheduledThreadPool(asyncConfigurerProperties.getSchedulerThreads(),
new ThreadFactoryBuilder().setNameFormat("central-scheduled-executor-pool-%d").build()));
}
/**
* @return {@link TaskScheduler} for task execution
*/
@Bean
@ConditionalOnMissingBean
public TaskScheduler taskScheduler() {
return new ConcurrentTaskScheduler(scheduledExecutorService());
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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.util.ArrayList;
import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator;
import org.eclipse.hawkbit.im.authentication.PermissionUtils;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.core.Authentication;
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;
/**
* Auto-configuration for the in-memory-user-management.
*
*/
@Configuration
@ConditionalOnMissingBean(UserDetailsService.class)
public class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter {
@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
@ConditionalOnMissingBean
public UserDetailsService userDetailsService() {
final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(new ArrayList<>());
inMemoryUserDetailsManager.setAuthenticationManager(null);
inMemoryUserDetailsManager.createUser(new User("admin", "admin", PermissionUtils.createAllAuthorityList()));
return inMemoryUserDetailsManager;
}
/**
* @return the multi-tenancy indicator to disallow multi-tenancy
*/
@Bean
@ConditionalOnMissingBean
public MultitenancyIndicator multiTenancyIndicator() {
return () -> false;
}
private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider {
@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;
}
}
}

View File

@@ -8,43 +8,17 @@
*/
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.DdiSecurityProperties;
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
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.
@@ -88,119 +62,4 @@ public class SecurityAutoConfiguration {
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);
}
}
}
}

View File

@@ -8,6 +8,10 @@
*/
package org.eclipse.hawkbit.autoconfigure.security;
import static com.google.common.collect.Lists.newArrayList;
import static org.springframework.context.annotation.AdviceMode.ASPECTJ;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
import java.io.IOException;
import java.net.URI;
@@ -26,10 +30,10 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.rest.resource.RestConstants;
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.DosFilter;
@@ -46,18 +50,19 @@ 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.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
import org.springframework.cache.Cache;
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.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.authentication.configuration.AuthenticationConfiguration;
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;
@@ -72,10 +77,13 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
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.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
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.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.session.SessionManagementFilter;
import org.vaadin.spring.security.VaadinSecurityContext;
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
import org.vaadin.spring.security.web.VaadinDefaultRedirectStrategy;
@@ -83,30 +91,49 @@ import org.vaadin.spring.security.web.VaadinRedirectStrategy;
import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler;
import com.google.common.collect.Lists;
/**
* All configurations related to SP authentication and authorization layer.
*
*
*
* All configurations related to HawkBit's authentication and authorization
* layer.
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = ASPECTJ, proxyTargetClass = true, securedEnabled = true)
@EnableWebMvcSecurity
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Order(value = HIGHEST_PRECEDENCE)
public class SecurityManagedConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(SecurityManagedConfiguration.class);
@Autowired
private HawkbitSecurityProperties securityProperties;
@Autowired
private AuthenticationConfiguration configuration;
/**
* @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
@ConditionalOnMissingBean
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);
}
}
/**
* {@link WebSecurityConfigurer} for the internal SP controller API.
*
*
*
*/
@Configuration
@Order(300)
@@ -114,19 +141,25 @@ public class SecurityManagedConfiguration {
@Autowired
private ControllerManagement controllerManagement;
@Autowired
private TenantConfigurationManagement tenantConfigurationManagement;
@Autowired
private TenantAware tenantAware;
@Autowired
private DdiSecurityProperties ddiSecurityConfiguration;
@Autowired
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Override
protected void configure(final HttpSecurity http) throws Exception {
final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
@@ -164,16 +197,19 @@ public class SecurityManagedConfiguration {
}
if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) {
LOG.info(
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
"******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************");
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous",
Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS),
newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS),
new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE)));
anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and()
.securityContext().disable().anonymous().authenticationFilter(anoymousFilter);
} else {
httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
.addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter)
.antMatcher("/*/controller/**").anonymous().disable().authorizeRequests().anyRequest()
@@ -186,6 +222,7 @@ public class SecurityManagedConfiguration {
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
ddiSecurityConfiguration.getRp().getTrustedIPs()));
}
@@ -200,6 +237,7 @@ public class SecurityManagedConfiguration {
@Bean
@Order(50)
public FilterRegistrationBean dosFilter() {
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(new DosFilter(securityProperties.getDos().getFilter().getMaxRead(),
@@ -207,6 +245,7 @@ public class SecurityManagedConfiguration {
securityProperties.getDos().getFilter().getWhitelist(), securityProperties.getClients().getBlacklist(),
securityProperties.getClients().getRemoteIpHeader()));
filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*");
return filterRegBean;
}
@@ -219,58 +258,49 @@ public class SecurityManagedConfiguration {
@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!
// Exclude 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;
private SecurityProperties springSecurityProperties;
@Override
protected void configure(final HttpSecurity http) throws Exception {
HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system.*").csrf().disable();
final BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName(springSecurityProperties.getBasic().getRealm());
HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system/admin.*").csrf().disable();
if (springSecurityProperties.isRequireSsl()) {
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
}
httpSec.addFilterBefore(new Filter() {
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
@@ -290,17 +320,17 @@ public class SecurityManagedConfiguration {
}, RequestHeaderAuthenticationFilter.class)
.addFilterAfter(
new AuthenticationSuccessTenantMetadataCreationFilter(tenantAware, systemManagement),
RequestHeaderAuthenticationFilter.class)
SessionManagementFilter.class)
.authorizeRequests().anyRequest().authenticated()
.antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN).antMatchers(RestConstants.BASE_SYSTEM_MAPPING + "/**")
.hasAnyAuthority(SpPermission.SYSTEM_DIAG);
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN);
httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
}
}
/**
* {@link WebSecurityConfigurer} for external (management) access.
*
*/
@Configuration
@Order(400)
@@ -310,10 +340,13 @@ public class SecurityManagedConfiguration {
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;
@Autowired
private HawkbitSecurityProperties securityProperties;
@@ -345,10 +378,13 @@ public class SecurityManagedConfiguration {
*/
@Bean
public VaadinAuthenticationSuccessHandler redirectSaveHandler() {
final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler();
handler.setRedirectStrategy(vaadinRedirectStrategy());
handler.setDefaultTargetUrl("/UI/");
handler.setTargetUrlParameter("r");
return handler;
}
@@ -370,7 +406,8 @@ public class SecurityManagedConfiguration {
// configuration xframe-option
final String confXframeOption = securityProperties.getXframe().getOption();
final String confAllowFromUri = securityProperties.getXframe().getAllowfrom();
if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri.isEmpty()) {
if (XFAME_OPTION_ALLOW_FROM.equals(confXframeOption) && confAllowFromUri.isEmpty()) {
// if allow-from option is specified but no allowFromUri throw
// exception
throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM"
@@ -379,9 +416,8 @@ public class SecurityManagedConfiguration {
}
// 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:
// 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
@@ -390,8 +426,9 @@ public class SecurityManagedConfiguration {
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******************\"");
"\"******************\\n** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **\\n******************\"");
}
// for UI integrator we allow frame integration on same origin
@@ -440,9 +477,6 @@ public class SecurityManagedConfiguration {
/**
* A Websecruity config to handle and filter the download ids.
*
*
*
*/
@Configuration
@EnableWebSecurity
@@ -458,6 +492,7 @@ public class SecurityManagedConfiguration {
@Override
protected void configure(final HttpSecurity http) throws Exception {
final HttpDownloadAuthenticationFilter downloadIdAuthenticationFilter = new HttpDownloadAuthenticationFilter(
downloadIdCache);
downloadIdAuthenticationFilter.setAuthenticationManager(authenticationManager());
@@ -475,32 +510,21 @@ public class SecurityManagedConfiguration {
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
ddiSecurityConfiguration.getRp().getTrustedIPs()));
}
}
}
/**
* 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());
@@ -514,14 +538,13 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
// has been fixed.
systemManagement.getTenantMetadata("DEFAULT");
}
super.onAuthenticationSuccess(authentication);
}
}
/**
* Sevletfilter to create metadata after successful authentication over RESTful.
*
*
*/
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
@@ -542,11 +565,13 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
@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);
}

View File

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

View File

@@ -11,4 +11,5 @@ 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.amqp.AmqpAutoConfiguration
org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.security.InMemoryUserManagementConfiguration

View File

@@ -7,6 +7,9 @@
# http://www.eclipse.org/legal/epl-v10.html
#
# Displayed basic auth realm
security.basic.realm=HawkBit
# JPA / Datasource
spring.jpa.eclipselink.eclipselink.weaving=false
spring.jpa.database=H2
@@ -27,12 +30,6 @@ vaadin.servlet.urlMapping=/UI/*
vaadin.servlet.heartbeatInterval=60
vaadin.servlet.closeIdleSessions=false
# Defines the thread pool executor
hawkbit.threadpool.corethreads=5
hawkbit.threadpool.maxthreads=20
hawkbit.threadpool.idletimeout=10000
hawkbit.threadpool.queuesize=20000
# Defines the polling time for the controllers in HH:MM:SS notation
hawkbit.controller.pollingTime=00:05:00
hawkbit.controller.pollingOverdueTime=00:05:00
@@ -44,4 +41,5 @@ hawkbit.controller.minPollingTime=00:00:30
# Configuration for RabbitMQ integration
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter_ttl
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
hawkbit.dmf.rabbitmq.authenticationReceiverQueue=authentication_receiver

View File

@@ -45,6 +45,12 @@
<!-- Test -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -15,6 +15,7 @@ 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.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@@ -50,8 +51,14 @@ public class RedisConfiguration {
* @return the spring redis cache manager.
*/
@Bean
@Primary
public CacheManager cacheManager() {
return new TenantAwareCacheManager(new RedisCacheManager(redisTemplate()), tenantAware);
return new TenantAwareCacheManager(directCacheManager(), tenantAware);
}
@Bean(name = "directCacheManager")
public CacheManager directCacheManager() {
return new RedisCacheManager(redisTemplate());
}
/**

View File

@@ -16,8 +16,8 @@ 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.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,7 +56,7 @@ public class EventDistributorTest {
@Test
public void distributeDistributedEventSendsToRedis() {
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
underTest.distribute(event);
// origin node ID should be set by distributing the event
@@ -67,7 +67,7 @@ public class EventDistributorTest {
@Test
public void dontDistributeDistributedEventIfSameNode() {
final String knownNodeId = EventDistributor.getNodeId();
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
event.setNodeId(knownNodeId);
// test
@@ -79,7 +79,7 @@ public class EventDistributorTest {
@Test
public void handleDistributedMessageFromRedis() {
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
final String knownChannel = "someChannel";
underTest.handleMessage(event, knownChannel);
@@ -90,7 +90,7 @@ public class EventDistributorTest {
@Test
public void handleDistributedMessageFilteredIfSameNodeId() {
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
final String knownChannel = "someChannel";
event.setOriginNodeId(EventDistributor.getNodeId());

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