diff --git a/examples/hawkbit-device-simulator/README.md b/examples/hawkbit-device-simulator/README.md
index b5db3d7ef..610a1d256 100644
--- a/examples/hawkbit-device-simulator/README.md
+++ b/examples/hawkbit-device-simulator/README.md
@@ -20,6 +20,25 @@ The simulator has user authentication enabled by default. Default credentials:
This can be configured/disabled by spring boot properties
## Usage
+
+### Graphical User Interface
+The device simulator comes with a graphical user interface which makes it very easy to generate dummy devices handled by the device simulator.
+The status and the update progress of the simulated device are shown in the UI.
+The UI can be accessed via the URL:
+```
+http://localhost:8083
+```
+
+`Basic Authentication Credentials are admin / admin`
+
+ 
+
+ 
+
+ 
+
+
+### REST API
The device simulator exposes an REST-API which can be used to trigger device creation.
Optional parameters:
diff --git a/examples/hawkbit-device-simulator/pom.xml b/examples/hawkbit-device-simulator/pom.xml
index 9e9fc86dc..eaec9b91e 100644
--- a/examples/hawkbit-device-simulator/pom.xml
+++ b/examples/hawkbit-device-simulator/pom.xml
@@ -80,10 +80,52 @@
org.springframework.boot
spring-boot-starter-log4j2
+
+ com.vaadin
+ vaadin-spring-boot-starter
+ 1.0.0
+
+
+ com.vaadin
+ vaadin-push
+
org.springframework.boot
spring-boot-autoconfigure
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+
+ com.google.guava
+ guava
+ 19.0
+
+
+ com.netflix.feign
+ feign-jackson
+ 8.14.1
+
+
+ com.netflix.feign
+ feign-core
+ 8.12.1
+
+
+ com.jayway.jsonpath
+ json-path
+
-
+
+
+
+ com.vaadin
+ vaadin-bom
+ 7.5.5
+ pom
+ import
+
+
+
diff --git a/examples/hawkbit-device-simulator/src/main/images/generateScreenshot.png b/examples/hawkbit-device-simulator/src/main/images/generateScreenshot.png
new file mode 100644
index 000000000..6c31c2d7d
Binary files /dev/null and b/examples/hawkbit-device-simulator/src/main/images/generateScreenshot.png differ
diff --git a/examples/hawkbit-device-simulator/src/main/images/updateProcessScreenshot.png b/examples/hawkbit-device-simulator/src/main/images/updateProcessScreenshot.png
new file mode 100644
index 000000000..dd3652790
Binary files /dev/null and b/examples/hawkbit-device-simulator/src/main/images/updateProcessScreenshot.png differ
diff --git a/examples/hawkbit-device-simulator/src/main/images/updateResultOverviewScreenshot.png b/examples/hawkbit-device-simulator/src/main/images/updateResultOverviewScreenshot.png
new file mode 100644
index 000000000..78e16758f
Binary files /dev/null and b/examples/hawkbit-device-simulator/src/main/images/updateResultOverviewScreenshot.png differ
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AbstractSimulatedDevice.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AbstractSimulatedDevice.java
new file mode 100644
index 000000000..474acb6c4
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AbstractSimulatedDevice.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+/**
+ * The bean of a simulated device which can be stored in the
+ * {@link DeviceSimulatorRepository} or shown in the UI.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public abstract class AbstractSimulatedDevice {
+
+ private String id;
+ private String tenant;
+ private Status status;
+ private double progress;
+ private String swversion = "unknown";
+ private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL;
+ private Protocol protocol = Protocol.DMF_AMQP;
+
+ private int nextPollCounterSec;
+
+ /**
+ * Enum definition of the protocol to be used for the simulated device.
+ *
+ * @author Michael Hirsch
+ *
+ */
+ public enum Protocol {
+ /**
+ * Device Management Federation API via AMQP, push mechanism.
+ */
+ DMF_AMQP,
+ /**
+ * Direct Device Interface via HTTP, poll mechanism.
+ */
+ DDI_HTTP;
+ }
+
+ /**
+ * The current status of the simulated device.
+ *
+ * @author Michael Hirsch
+ *
+ */
+ public enum Status {
+ /**
+ * device is in status unknown.
+ */
+ UNKNWON,
+ /**
+ * device is in status pending which represents is updating software.
+ */
+ PEDNING,
+ /**
+ * device has been updated successfully.
+ */
+ FINISH,
+ /**
+ * device has been updated with an error.
+ */
+ ERROR;
+ }
+
+ /**
+ * The status to response to the hawkbit update server if an simulated
+ * update process should be respond with successful or failure update.
+ *
+ * @author Michael Hirsch
+ *
+ */
+ public enum ResponseStatus {
+ /**
+ * updated has been successful and response the successful update.
+ */
+ SUCCESSFUL,
+ /**
+ * updated has been not successful and response the error update.
+ */
+ ERROR;
+ }
+
+ /**
+ * empty constructor.
+ */
+ AbstractSimulatedDevice() {
+
+ }
+
+ /**
+ * Creates a new simulated device.
+ *
+ * @param id
+ * the ID of the simulated device
+ * @param tenant
+ * the tenant of the simulated device
+ */
+ AbstractSimulatedDevice(final String id, final String tenant, final Protocol protocol) {
+ this.id = id;
+ this.tenant = tenant;
+ this.status = Status.UNKNWON;
+ this.progress = 0.0;
+ this.protocol = protocol;
+ }
+
+ /**
+ * Method to clean-up resource e.g. when the simulated device has been
+ * removed from the repository.
+ */
+ public void clean() {
+
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+
+ public double getProgress() {
+ return progress;
+ }
+
+ public String getTenant() {
+ return tenant;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public void setTenant(final String tenant) {
+ this.tenant = tenant;
+ }
+
+ public void setStatus(final Status status) {
+ this.status = status;
+ }
+
+ public void setProgress(final double progress) {
+ this.progress = progress;
+ }
+
+ public String getSwversion() {
+ return swversion;
+ }
+
+ public void setSwversion(final String swversion) {
+ this.swversion = swversion;
+ }
+
+ public ResponseStatus getResponseStatus() {
+ return responseStatus;
+ }
+
+ public void setResponseStatus(final ResponseStatus responseStatus) {
+ this.responseStatus = responseStatus;
+ }
+
+ public Protocol getProtocol() {
+ return protocol;
+ }
+
+ public int getNextPollCounterSec() {
+ return nextPollCounterSec;
+ }
+
+ public void setNextPollCounterSec(final int nextPollDelayInSec) {
+ this.nextPollCounterSec = nextPollDelayInSec;
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DDISimulatedDevice.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DDISimulatedDevice.java
new file mode 100644
index 000000000..1417c3153
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DDISimulatedDevice.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater.UpdaterCallback;
+import org.eclipse.hawkbit.simulator.http.ControllerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.jayway.jsonpath.JsonPath;
+import com.jayway.jsonpath.PathNotFoundException;
+
+/**
+ * @author Michael Hirsch
+ *
+ */
+public class DDISimulatedDevice extends AbstractSimulatedDevice {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class);
+
+ private final int pollDelaySec;
+ private final ScheduledExecutorService pollthreadpool;
+ private final ControllerResource controllerResource;
+
+ private volatile boolean removed;
+ private volatile Long currentActionId;
+ private final DeviceSimulatorUpdater deviceUpdater;
+
+ /**
+ * @param id
+ * the ID of the device
+ * @param tenant
+ * the tenant of the simulated device
+ * @param pollDelaySec
+ * the delay of the poll interval in sec
+ * @param controllerResource
+ * the http controller resource
+ * @param pollthreadpool
+ * the threadpool for polling endpoint
+ * @param deviceUpdater
+ * the service to update devices
+ */
+ public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec,
+ final ControllerResource controllerResource, final ScheduledExecutorService pollthreadpool,
+ final DeviceSimulatorUpdater deviceUpdater) {
+ super(id, tenant, Protocol.DDI_HTTP);
+ this.pollDelaySec = pollDelaySec;
+ this.controllerResource = controllerResource;
+ this.pollthreadpool = pollthreadpool;
+ this.deviceUpdater = deviceUpdater;
+ setNextPollCounterSec(pollDelaySec);
+ }
+
+ @Override
+ public void clean() {
+ super.clean();
+ removed = true;
+ }
+
+ public int getPollDelaySec() {
+ return pollDelaySec;
+ }
+
+ /**
+ * Polls the base URL for the DDI API interface.
+ */
+ public void poll() {
+ if (!removed) {
+ final String basePollJson = controllerResource.get(getTenant(), getId());
+ try {
+ final String href = JsonPath.parse(basePollJson).read("_links.deploymentBase.href");
+ final long actionId = Long.parseLong(href.substring(href.lastIndexOf("/") + 1, href.indexOf("?")));
+ if (currentActionId == null) {
+ final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId);
+ final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version");
+ currentActionId = actionId;
+ deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, new UpdaterCallback() {
+ @Override
+ public void updateFinished(final AbstractSimulatedDevice device, final Long actionId) {
+ switch (device.getResponseStatus()) {
+ case SUCCESSFUL:
+ controllerResource.postSuccessFeedback(getTenant(), getId(), actionId);
+ break;
+ case ERROR:
+ controllerResource.postErrorFeedback(getTenant(), getId(), actionId);
+ break;
+ default:
+ throw new IllegalStateException("simulated device has an unknown response status + "
+ + device.getResponseStatus());
+ }
+ currentActionId = null;
+ }
+ });
+ }
+ } catch (final PathNotFoundException e) {
+ // href might not be in the json response, so ignore
+ // exception here.
+ LOGGER.trace("Response does not contain a deploymentbase href link, ignoring.");
+ }
+
+ }
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DMFSimulatedDevice.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DMFSimulatedDevice.java
new file mode 100644
index 000000000..b9fdc827c
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DMFSimulatedDevice.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+/**
+ * An simulated device using the DMF API of the hawkbit update server.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public class DMFSimulatedDevice extends AbstractSimulatedDevice {
+
+ /**
+ * @param id
+ * the ID of the device
+ * @param tenant
+ * the tenant of the simulated device
+ */
+ public DMFSimulatedDevice(final String id, final String tenant) {
+ super(id, tenant, Protocol.DMF_AMQP);
+ }
+
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java
index 37812a19d..944ba1d07 100644
--- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java
@@ -8,8 +8,15 @@
*/
package org.eclipse.hawkbit.simulator;
+import java.util.concurrent.Executors;
+
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.EventBus;
+import com.vaadin.spring.annotation.EnableVaadin;
/**
* The main-method to start the Spring-Boot application.
@@ -18,12 +25,21 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*
*/
@SpringBootApplication
+@EnableVaadin
public class DeviceSimulator {
- private DeviceSimulator() {
+ public DeviceSimulator() {
// utility class
}
+ /**
+ * @return an asynchronous event bus to publish and retrieve events.
+ */
+ @Bean
+ public EventBus eventBus() {
+ return new AsyncEventBus(Executors.newFixedThreadPool(4));
+ }
+
/**
* Start the Spring Boot Application.
*
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorRepository.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorRepository.java
new file mode 100644
index 000000000..68db9df45
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorRepository.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * An in-memory simulated device repository to hold the simulated device in
+ * memory and be able to retrieve them again.
+ *
+ * @author Michael Hirsch
+ *
+ */
+@Service
+public class DeviceSimulatorRepository {
+
+ private final Map devices = new LinkedHashMap<>();
+
+ @Autowired
+ private SimulatedDeviceFactory deviceFactory;
+
+ /**
+ * Adds a simulated device to the repository.
+ *
+ * @param simulatedDevice
+ * the device to add
+ * @return the device which has been added to the repository
+ */
+ public AbstractSimulatedDevice add(final AbstractSimulatedDevice simulatedDevice) {
+ devices.put(new DeviceKey(simulatedDevice.getTenant().toLowerCase(), simulatedDevice.getId()), simulatedDevice);
+ return simulatedDevice;
+ }
+
+ /**
+ * @return all simulated devices
+ */
+ public Collection getAll() {
+ return devices.values();
+ }
+
+ /**
+ * Retrieves a single simulated devices or {@code null} if device does not
+ * exists.
+ *
+ * @param tenant
+ * the tenant of the simulated device
+ * @param id
+ * the ID of the device
+ * @return a simulated device from the repository or {@code null} if device
+ * does not exixts.
+ */
+ public AbstractSimulatedDevice get(final String tenant, final String id) {
+ return devices.get(new DeviceKey(tenant.toLowerCase(), id));
+ }
+
+ /**
+ * Clears all stored devices.
+ */
+ public void clear() {
+ devices.values().forEach(device -> device.clean());
+ devices.clear();
+ }
+
+ private static final class DeviceKey {
+ private final String tenant;
+ private final String id;
+
+ private DeviceKey(final String tenant, final String id) {
+ this.tenant = tenant;
+ this.id = id;
+ }
+
+ @Override
+ public int hashCode() {// NOSONAR - as this is generated
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((tenant == null) ? 0 : tenant.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {// NOSONAR - as this is
+ // generated
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final DeviceKey other = (DeviceKey) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (tenant == null) {
+ if (other.tenant != null) {
+ return false;
+ }
+ } else if (!tenant.equals(other.tenant)) {
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java
new file mode 100644
index 000000000..6e93b7d04
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+import java.util.Random;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
+import org.eclipse.hawkbit.simulator.event.InitUpdate;
+import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.google.common.eventbus.EventBus;
+
+/**
+ * @author Michael Hirsch
+ *
+ */
+@Service
+public class DeviceSimulatorUpdater {
+
+ private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4);
+
+ @Autowired
+ private SpSenderService spSenderService;
+
+ @Autowired
+ private EventBus eventbus;
+
+ @Autowired
+ private DeviceSimulatorRepository repository;
+
+ /**
+ * Starting an simulated update process of an simulated device.
+ *
+ * @param tenant
+ * the tenant of the device
+ * @param id
+ * the ID of the simulated device
+ * @param actionId
+ * the actionId from the hawkbit update server to start the
+ * update.
+ * @param swVersion
+ * the software module version from the hawkbit update server
+ * @param callback
+ * the callback which gets called when the simulated update
+ * process has been finished
+ */
+ public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion,
+ final UpdaterCallback callback) {
+ final AbstractSimulatedDevice device = repository.get(tenant, id);
+ device.setProgress(0.0);
+ device.setSwversion(swVersion);
+ eventbus.post(new InitUpdate(device));
+ threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback),
+ 2000, TimeUnit.MILLISECONDS);
+ }
+
+ private static final class DeviceSimulatorUpdateThread implements Runnable {
+ private static final Random rndSleep = new Random();
+
+ private final AbstractSimulatedDevice device;
+ private final SpSenderService spSenderService;
+ private final long actionId;
+ private final EventBus eventbus;
+ private final UpdaterCallback callback;
+
+ private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device,
+ final SpSenderService spSenderService, final long actionId, final EventBus eventbus,
+ final UpdaterCallback callback) {
+ this.device = device;
+ this.spSenderService = spSenderService;
+ this.actionId = actionId;
+ this.eventbus = eventbus;
+ this.callback = callback;
+ }
+
+ @Override
+ public void run() {
+ final double newProgress = device.getProgress() + 0.2;
+ device.setProgress(newProgress);
+ if (newProgress < 1.0) {
+ threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus,
+ callback), rndSleep.nextInt(3000), TimeUnit.MILLISECONDS);
+ } else {
+ callback.updateFinished(device, actionId);
+ }
+ eventbus.post(new ProgressUpdate(device));
+ }
+ }
+
+ /**
+ * Callback interface which is called when the simulated update process has
+ * been finished and the caller of starting the simulated update process can
+ * send the result to the hawkbit update server back.
+ *
+ * @author Michael Hirsch
+ *
+ */
+ @FunctionalInterface
+ public interface UpdaterCallback {
+ /**
+ * Callback method to indicate that the simulated update process has
+ * been finished.
+ *
+ * @param device
+ * the device which has been updated
+ * @param actionId
+ * the ID of the action from the hawkbit update server
+ */
+ void updateFinished(AbstractSimulatedDevice device, final Long actionId);
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/NextPollTimeController.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/NextPollTimeController.java
new file mode 100644
index 000000000..81acf897e
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/NextPollTimeController.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+import java.util.List;
+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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.google.common.eventbus.EventBus;
+
+/**
+ * Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every
+ * second.
+ *
+ * @author Michael Hirsch
+ *
+ */
+@Component
+public class NextPollTimeController {
+
+ private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
+ private static final ExecutorService pollService = Executors.newFixedThreadPool(1);
+
+ @Autowired
+ private DeviceSimulatorRepository repository;
+
+ @Autowired
+ private EventBus eventBus;
+
+ /**
+ * Constructor which schedules the poll trigger runnable every second.
+ */
+ public NextPollTimeController() {
+ executorService.scheduleWithFixedDelay(new NextPollUpdaterRunnable(), 1, 1, TimeUnit.SECONDS);
+ }
+
+ private class NextPollUpdaterRunnable implements Runnable {
+ @Override
+ public void run() {
+ final List devices = repository.getAll().stream()
+ .filter(device -> device instanceof DDISimulatedDevice).collect(Collectors.toList());
+
+ devices.forEach(device -> {
+ int nextCounter = device.getNextPollCounterSec() - 1;
+ if (nextCounter < 0) {
+ if (device instanceof DDISimulatedDevice) {
+ try {
+ pollService.submit(new Runnable() {
+ @Override
+ public void run() {
+ ((DDISimulatedDevice) device).poll();
+ }
+ });
+ } catch (final Exception e) {
+
+ }
+ nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
+ }
+ }
+ device.setNextPollCounterSec(nextCounter);
+ });
+ eventBus.post(new NextPollCounterUpdate(devices));
+ }
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java
new file mode 100644
index 000000000..d3e080806
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+import java.net.URL;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
+import org.eclipse.hawkbit.simulator.http.ControllerResource;
+import org.eclipse.hawkbit.simulator.http.GatewayTokenInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import feign.Feign;
+import feign.Logger;
+
+/**
+ * The simulated device factory to create either {@link DMFSimulatedDevice} or
+ * {@link DDISimulatedDevice#}.
+ *
+ * @author Michael Hirsch
+ *
+ */
+@Service
+public class SimulatedDeviceFactory {
+
+ private static final ScheduledExecutorService pollThreadPool = Executors.newScheduledThreadPool(4);
+
+ @Autowired
+ private DeviceSimulatorUpdater deviceUpdater;
+
+ /**
+ * Creating a simulated devices.
+ *
+ * @param id
+ * the ID of the simulated device
+ * @param tenant
+ * the tenant of the simulated device
+ * @param protocol
+ * the protocol of the device
+ * @return the created simulated device
+ */
+ public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol) {
+ return createSimulatedDevice(id, tenant, protocol, 30, null, null);
+ }
+
+ /**
+ * Creating a simulated device.
+ *
+ * @param id
+ * the ID of the simulated device
+ * @param tenant
+ * the tenant of the simulated device
+ * @param protocol
+ * 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
+ * @param baseEndpoint
+ * the http base endpoint which should be used for
+ * {@link DDISimulatedDevice}s
+ * @param gatewayToken
+ * the gatewayToken to be used to authenticate
+ * {@link DDISimulatedDevice}s at the endpoint
+ * @return the created simulated device
+ */
+ public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol,
+ final int pollDelaySec, final URL baseEndpoint, final String gatewayToken) {
+ switch (protocol) {
+ case DMF_AMQP:
+ return new DMFSimulatedDevice(id, tenant);
+ case DDI_HTTP:
+ final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger())
+ .requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC)
+ .target(ControllerResource.class, baseEndpoint.toString());
+ return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, pollThreadPool, deviceUpdater);
+ default:
+ throw new IllegalArgumentException("Protocol " + protocol + " unknown");
+ }
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java
index ab8847cb1..6f94bd319 100644
--- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java
@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.simulator;
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -26,6 +27,12 @@ public class SimulationController {
@Autowired
private SpSenderService spSenderService;
+ @Autowired
+ private DeviceSimulatorRepository repository;
+
+ @Autowired
+ private SimulatedDeviceFactory deviceFactory;
+
/**
* The start resource to start a device creation.
*
@@ -43,7 +50,9 @@ public class SimulationController {
@RequestParam(value = "tenant", defaultValue = "DEFAULT") final String tenant) {
for (int i = 0; i < amount; i++) {
- spSenderService.createOrUpdateThing(tenant, name + i);
+ final String deviceId = name + i;
+ repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, Protocol.DMF_AMQP));
+ spSenderService.createOrUpdateThing(tenant, deviceId);
}
return "Updated " + amount + " DMF connected targets!";
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
index c4968c849..492bb3857 100644
--- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
@@ -132,6 +132,9 @@ public class AmqpConfiguration {
final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
containerFactory.setDefaultRequeueRejected(false);
containerFactory.setConnectionFactory(connectionFactory);
+ containerFactory.setConcurrentConsumers(20);
+ containerFactory.setMaxConcurrentConsumers(20);
+ containerFactory.setPrefetchCount(20);
return containerFactory;
}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java
index 5884a2645..6f0ac732e 100644
--- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java
@@ -15,6 +15,9 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.ActionStatus;
import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
+import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater;
+import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater.UpdaterCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
@@ -40,6 +43,8 @@ public class SpReceiverService extends ReceiverService {
private final SpSenderService spSenderService;
+ private final DeviceSimulatorUpdater deviceUpdater;
+
/**
* Constructor.
*
@@ -51,12 +56,15 @@ public class SpReceiverService extends ReceiverService {
* the lwm2mSenderService
* @param spSenderService
* the spSenderService
+ * @param deviceUpdater
+ * the updater service to simulate update process
*/
@Autowired
public SpReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties,
- final SpSenderService spSenderService) {
+ final SpSenderService spSenderService, final DeviceSimulatorUpdater deviceUpdater) {
super(rabbitTemplate, amqpProperties);
this.spSenderService = spSenderService;
+ this.deviceUpdater = deviceUpdater;
}
@@ -139,16 +147,23 @@ public class SpReceiverService extends ReceiverService {
spSenderService.sendActionStatusMessage(tenant, ActionStatus.RUNNING,
"device Simulator retrieved update request. proceeding with simulation.", actionId);
-
- final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId);
-
- try {
- Thread.sleep(1_000);
- } catch (final InterruptedException e) {
- LOGGER.error("Sleep interrupted", e);
- }
-
- spSenderService.finishUpdateProcess(update, "Simulation complete!");
+ deviceUpdater.startUpdate(tenant, thingId, actionId, downloadAndUpdateRequest.getSoftwareModules().get(0)
+ .getModuleVersion(), new UpdaterCallback() {
+ @Override
+ public void updateFinished(final AbstractSimulatedDevice device, final Long actionId) {
+ switch (device.getResponseStatus()) {
+ case SUCCESSFUL:
+ spSenderService.finishUpdateProcess(new SimulatedUpdate(device.getTenant(), device.getId(),
+ actionId), "Simulation complete!");
+ break;
+ case ERROR:
+ spSenderService.finishUpdateProcessWithError(new SimulatedUpdate(device.getTenant(),
+ device.getId(), actionId), "Simulation complete with error!");
+ break;
+ default:
+ break;
+ }
+ }
+ });
}
-
}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/InitUpdate.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/InitUpdate.java
new file mode 100644
index 000000000..1cf6dbbda
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/InitUpdate.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.event;
+
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
+
+/**
+ * Event description which indicates the initialization of an update.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public class InitUpdate {
+
+ private final AbstractSimulatedDevice device;
+
+ /**
+ * Creates new progress update event.
+ *
+ * @param device
+ * the device which progress has been updated
+ */
+ public InitUpdate(final AbstractSimulatedDevice device) {
+ this.device = device;
+ }
+
+ /**
+ * @return the device of the event
+ */
+ public AbstractSimulatedDevice getDevice() {
+ return device;
+ }
+
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/NextPollCounterUpdate.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/NextPollCounterUpdate.java
new file mode 100644
index 000000000..b9d7b9027
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/NextPollCounterUpdate.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.event;
+
+import java.util.List;
+
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
+
+/**
+ * Event description which indicates an poll time update.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public class NextPollCounterUpdate {
+
+ private final List devices;
+
+ /**
+ * Creates poll timer update event.
+ *
+ * @param devices
+ * the devices which progress has been updated
+ */
+ public NextPollCounterUpdate(final List devices) {
+ this.devices = devices;
+ }
+
+ /**
+ * @return the devices of the event
+ */
+ public List getDevices() {
+ return devices;
+ }
+
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/ProgressUpdate.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/ProgressUpdate.java
new file mode 100644
index 000000000..3e34a0fa1
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/ProgressUpdate.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.event;
+
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
+
+/**
+ * Event definition object which is published if the simulated device updated
+ * its update progress.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public class ProgressUpdate {
+
+ private final AbstractSimulatedDevice device;
+
+ /**
+ * Creates new progress update event.
+ *
+ * @param device
+ * the device which progress has been updated
+ */
+ public ProgressUpdate(final AbstractSimulatedDevice device) {
+ this.device = device;
+ }
+
+ /**
+ * @return the device of the event
+ */
+ public AbstractSimulatedDevice getDevice() {
+ return device;
+ }
+
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/http/ControllerResource.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/http/ControllerResource.java
new file mode 100644
index 000000000..1dac4c80b
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/http/ControllerResource.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.http;
+
+import org.eclipse.hawkbit.simulator.DDISimulatedDevice;
+
+import feign.Body;
+import feign.Headers;
+import feign.Param;
+import feign.RequestLine;
+
+/**
+ * A feign based controller resource interface declaration for
+ * {@link DDISimulatedDevice}s using over HTTP.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public interface ControllerResource {
+
+ /**
+ * The base poll URL for the devices to retrieve if there is an update
+ * available.
+ *
+ * @param tenant
+ * the tenant of the device
+ * @param controllerId
+ * the ID of the device
+ * @return the plain json response of the http request
+ */
+ @RequestLine("GET /{tenant}/controller/v1/{controllerId}")
+ @Headers({ "Content-Type: application/json" })
+ String get(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId);
+
+ /**
+ * Retrieving the deployment job response from the hawkbit update server.
+ *
+ * @param tenant
+ * the tenant for the simulated device
+ * @param controllerId
+ * the ID of the device
+ * @param actionId
+ * the ID of the action to retrieve
+ * @return the json response of the http request
+ */
+ @RequestLine("GET /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}")
+ @Headers({ "Content-Type: application/json" })
+ String getDeployment(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId,
+ @Param("actionId") final long actionId);
+
+ /**
+ * Post a success update feedback to the hawkbit update server
+ *
+ * @param tenant
+ * the tenant of the device
+ * @param controllerId
+ * the ID of the device
+ * @param actionId
+ * the ID of the action to post feedback back
+ */
+ @RequestLine("POST /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}/feedback")
+ @Headers("Content-Type: application/json")
+ @Body("%7B\"id\":{actionId},\"time\":\"20140511T121314\",\"status\":%7B\"execution\":\"closed\",\"result\":%7B\"finished\":\"success\",\"progress\":%7B%7D%7D%7D%7D")
+ void postSuccessFeedback(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId,
+ @Param("actionId") final long actionId);
+
+ /**
+ * Post a failure update feedback to the hawkbit update server
+ *
+ * @param tenant
+ * the tenant of the device
+ * @param controllerId
+ * the ID of the device
+ * @param actionId
+ * the ID of the action to post feedback back
+ */
+ @RequestLine("POST /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}/feedback")
+ @Headers("Content-Type: application/json")
+ @Body("%7B\"id\":{actionId},\"time\":\"20140511T121314\",\"status\":%7B\"execution\":\"closed\",\"result\":%7B\"finished\":\"failure\",\"progress\":%7B%7D%7D%7D%7D")
+ void postErrorFeedback(@Param("tenant") final String tenant, @Param("controllerId") final String controllerId,
+ @Param("actionId") final long actionId);
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/http/GatewayTokenInterceptor.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/http/GatewayTokenInterceptor.java
new file mode 100644
index 000000000..3381481de
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/http/GatewayTokenInterceptor.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.http;
+
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+
+/**
+ * A feign interceptor to apply the gateway-token header to each http-request.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public class GatewayTokenInterceptor implements RequestInterceptor {
+
+ private final String gatewayToken;
+
+ /**
+ * @param gatewayToken
+ * the gatwway token to be used in the http-header
+ */
+ public GatewayTokenInterceptor(final String gatewayToken) {
+ this.gatewayToken = gatewayToken;
+ }
+
+ @Override
+ public void apply(final RequestTemplate template) {
+ template.header("Authorization", "GatewayToken " + gatewayToken);
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java
new file mode 100644
index 000000000..1400ec0e1
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java
@@ -0,0 +1,233 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.ui;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.util.ObjectProperty;
+import com.vaadin.data.validator.NullValidator;
+import com.vaadin.data.validator.RangeValidator;
+import com.vaadin.data.validator.RegexpValidator;
+import com.vaadin.server.FontAwesome;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.OptionGroup;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Window;
+
+/**
+ * Popup dialog window for setting the values of generating the simulated
+ * devices, e.g. the amount.
+ *
+ * @author Michael Hirsch
+ *
+ */
+public class GenerateDialog extends Window {
+
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOGGER = LoggerFactory.getLogger(GenerateDialog.class);
+
+ private final FormLayout formLayout = new FormLayout();
+
+ /**
+ * Creates a new pop window for setting the configuration of simulating
+ * devices.
+ *
+ * @param callback
+ * the callback which is called when the dialog has been
+ * successfully confirmed.
+ */
+ public GenerateDialog(final GenerateDialogCallback callback) {
+
+ formLayout.setSpacing(true);
+ formLayout.setMargin(true);
+
+ final TextField tf1 = new TextField("name prefix", "dmfSimulated");
+ tf1.setIcon(FontAwesome.INFO);
+ tf1.setRequired(true);
+ tf1.addValidator(new NullValidator("Must be given", false));
+
+ final TextField tf2 = new TextField("amount", new ObjectProperty(10));
+ tf2.setIcon(FontAwesome.GEAR);
+ tf2.setRequired(true);
+ tf2.addValidator(new RangeValidator("Must be between 1 and 30000", Integer.class, 1, 30000));
+
+ final TextField tf3 = new TextField("tenant", "default");
+ tf3.setIcon(FontAwesome.USER);
+ tf3.setRequired(true);
+ tf3.addValidator(new NullValidator("Must be given", false));
+
+ final TextField tf4 = new TextField("poll delay (sec)", new ObjectProperty(10));
+ tf4.setIcon(FontAwesome.CLOCK_O);
+ tf4.setRequired(true);
+ tf4.setVisible(false);
+ tf4.addValidator(new RangeValidator("Must be between 1 and 60", Integer.class, 1, 60));
+
+ final TextField tf5 = new TextField("base poll URL endpoint", "http://localhost:8080");
+ tf5.setColumns(50);
+ tf5.setIcon(FontAwesome.FLAG_O);
+ tf5.setRequired(true);
+ tf5.setVisible(false);
+ tf5.addValidator(new RegexpValidator(
+ "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]", "is not an URL"));
+
+ final TextField tf6 = new TextField("gateway token", "");
+ tf6.setColumns(50);
+ tf6.setIcon(FontAwesome.FLAG_O);
+ tf6.setRequired(true);
+ tf6.setVisible(false);
+
+ final OptionGroup protocolGroup = new OptionGroup("Simulated Device Protocol");
+ protocolGroup.addItem(Protocol.DMF_AMQP);
+ protocolGroup.addItem(Protocol.DDI_HTTP);
+ protocolGroup.setItemCaption(Protocol.DMF_AMQP, "Device Management Federation API (AMQP push)");
+ protocolGroup.setItemCaption(Protocol.DDI_HTTP, "Direct Device Interface (HTTP poll)");
+ protocolGroup.setNullSelectionAllowed(false);
+ protocolGroup.select(Protocol.DMF_AMQP);
+ protocolGroup.addValueChangeListener(new ValueChangeListener() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void valueChange(final ValueChangeEvent event) {
+ if (event.getProperty().getValue().equals(Protocol.DDI_HTTP)) {
+ tf4.setVisible(true);
+ tf5.setVisible(true);
+ tf6.setVisible(true);
+ } else {
+ tf4.setVisible(false);
+ tf5.setVisible(false);
+ tf6.setVisible(false);
+ }
+ }
+ });
+
+ final Button buttonOk = new Button("generate");
+ buttonOk.setImmediate(true);
+ buttonOk.setIcon(FontAwesome.GEARS);
+ buttonOk.addClickListener(new ClickListener() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(final ClickEvent event) {
+ try {
+ callback.okButton(tf1.getValue(), tf3.getValue(), Integer.valueOf(tf2.getValue().replace(".", "")),
+ Integer.valueOf(tf4.getValue().replace(".", "")), new URL(tf5.getValue()), tf6.getValue(),
+ (Protocol) protocolGroup.getValue());
+ } catch (final NumberFormatException e) {
+ LOGGER.info(e.getMessage(), e);
+ } catch (final MalformedURLException e) {
+ LOGGER.info(e.getMessage(), e);
+ }
+ GenerateDialog.this.close();
+ }
+ });
+
+ tf1.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
+ tf2.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
+ tf3.addValueChangeListener(event -> checkValid(tf1, tf2, tf3, tf4, buttonOk));
+
+ formLayout.addComponent(tf1);
+ formLayout.addComponent(tf2);
+ formLayout.addComponent(tf3);
+ formLayout.addComponent(protocolGroup);
+ formLayout.addComponent(tf4);
+ formLayout.addComponent(tf5);
+ formLayout.addComponent(tf6);
+ formLayout.addComponent(buttonOk);
+
+ setCaption("Simulate Devices");
+ setContent(formLayout);
+ setResizable(false);
+ center();
+ }
+
+ private void checkValid(final TextField tf1, final TextField tf2, final TextField tf3, final TextField tf4,
+ final Button buttonOk) {
+ if (tf1.isValid() && tf2.isValid() && tf3.isValid() && tf4.isValid()) {
+ buttonOk.setEnabled(true);
+ } else {
+ buttonOk.setEnabled(false);
+ }
+ }
+
+ @Override
+ public int hashCode() {// NOSONAR - as this is generated
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((formLayout == null) ? 0 : formLayout.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {// NOSONAR - as this is generated
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final GenerateDialog other = (GenerateDialog) obj;
+ if (formLayout == null) {
+ if (other.formLayout != null) {
+ return false;
+ }
+ } else if (!formLayout.equals(other.formLayout)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Callback interface to retrieve the result from the dialog window.
+ *
+ * @author Michael Hirsch
+ *
+ */
+ @FunctionalInterface
+ interface GenerateDialogCallback {
+ /**
+ * Callback method which is called when dialog closes with the OK
+ * button.
+ *
+ * @param namePrefix
+ * the parameter for name prefix for the simulated devices
+ * @param tenant
+ * the tenant for the simulated devices
+ * @param amount
+ * the number of simulated devices to be created
+ * @param pollDelay
+ * the delay poll time in seconds for DDI devices
+ * @param basePollURL
+ * the base http URL endpoint for DDI devices
+ * @param gatewayToken
+ * the gateway token header for authentication for DDI
+ * devices
+ * @param protocol
+ * the protocol to be used for the simulated devices to be
+ * generated
+ */
+ void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay,
+ final URL basePollURL, final String gatewayToken, final Protocol protocol);
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorUI.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorUI.java
new file mode 100644
index 000000000..1c09a702d
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorUI.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.ui;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.vaadin.annotations.Push;
+import com.vaadin.annotations.Theme;
+import com.vaadin.annotations.Title;
+import com.vaadin.navigator.Navigator;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.communication.PushMode;
+import com.vaadin.shared.ui.ui.Transport;
+import com.vaadin.spring.annotation.SpringUI;
+import com.vaadin.spring.navigator.SpringViewProvider;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * The vaadin simulator UI which allows to generate simulated devices and show
+ * their current status and update progress.
+ *
+ * @author Michael Hirsch
+ *
+ */
+@SpringUI(path = "")
+@Title("hawkBit Device Simulator")
+@Theme(value = "simulator")
+@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET)
+public class SimulatorUI extends UI {
+
+ private static final long serialVersionUID = 1L;
+
+ private final VerticalLayout rootLayout = new VerticalLayout();
+
+ @Autowired
+ private SpringViewProvider viewProvider;
+
+ @Override
+ protected void init(final VaadinRequest request) {
+
+ rootLayout.setSizeFull();
+
+ final Panel viewContainer = new Panel();
+ viewContainer.setSizeFull();
+ rootLayout.addComponent(viewContainer);
+ rootLayout.setExpandRatio(viewContainer, 1.0F);
+
+ final Navigator navigator = new Navigator(this, viewContainer);
+ navigator.addProvider(viewProvider);
+
+ setContent(rootLayout);
+ }
+
+}
diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorView.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorView.java
new file mode 100644
index 000000000..25498cea7
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorView.java
@@ -0,0 +1,341 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator.ui;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Locale;
+
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.ResponseStatus;
+import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Status;
+import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
+import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory;
+import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
+import org.eclipse.hawkbit.simulator.event.InitUpdate;
+import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
+import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
+import org.eclipse.hawkbit.simulator.ui.GenerateDialog.GenerateDialogCallback;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.google.common.collect.Lists;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.util.BeanContainer;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.data.util.converter.Converter;
+import com.vaadin.navigator.View;
+import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
+import com.vaadin.server.FontAwesome;
+import com.vaadin.spring.annotation.SpringView;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.CellReference;
+import com.vaadin.ui.Grid.CellStyleGenerator;
+import com.vaadin.ui.Grid.SelectionMode;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.renderers.HtmlRenderer;
+import com.vaadin.ui.renderers.ProgressBarRenderer;
+
+/**
+ * Vaadin view which allows to generate devices through the DMF API and show the
+ * current simulated devices in a grid with their current status and update
+ * progress.
+ *
+ * @author Michael Hirsch
+ *
+ */
+@SpringView(name = "")
+public class SimulatorView extends VerticalLayout implements View {
+
+ private static final long serialVersionUID = 1L;
+
+ @Autowired
+ private transient SpSenderService spSenderService;
+ @Autowired
+ private transient DeviceSimulatorRepository repository;
+ @Autowired
+ private transient SimulatedDeviceFactory deviceFactory;
+
+ @Autowired
+ private transient EventBus eventbus;
+
+ private final Label caption = new Label("DMF/DDI Simulated Devices");
+ private final HorizontalLayout toolbar = new HorizontalLayout();
+ private final Grid grid = new Grid();
+ private final ComboBox responseComboBox = new ComboBox("", Lists.newArrayList(ResponseStatus.SUCCESSFUL,
+ ResponseStatus.ERROR));
+
+ private BeanContainer beanContainer;
+
+ @Override
+ public void enter(final ViewChangeEvent event) {
+ eventbus.register(this);
+ setSizeFull();
+
+ // caption
+ caption.addStyleName("h2");
+
+ // toolbar
+ createToolbar();
+
+ beanContainer = new BeanContainer<>(AbstractSimulatedDevice.class);
+ beanContainer.setBeanIdProperty("id");
+
+ grid.setSizeFull();
+ grid.setCellStyleGenerator(new CellStyleGenerator() {
+ @Override
+ public String getStyle(final CellReference cellReference) {
+ return cellReference.getPropertyId().equals("status") ? "centeralign" : null;
+ }
+ });
+
+ grid.setSelectionMode(SelectionMode.NONE);
+ grid.setContainerDataSource(beanContainer);
+ grid.appendHeaderRow().getCell("responseStatus").setComponent(responseComboBox);
+ grid.setColumnOrder("id", "status", "swversion", "progress", "tenant", "protocol", "responseStatus",
+ "nextPollCounterSec");
+ // header widths
+ grid.getColumn("status").setMaximumWidth(80);
+ grid.getColumn("protocol").setMaximumWidth(180);
+ grid.getColumn("responseStatus").setMaximumWidth(240);
+ grid.getColumn("nextPollCounterSec").setMaximumWidth(210);
+
+ grid.getColumn("nextPollCounterSec").setHeaderCaption("Next Poll in (sec)");
+ grid.getColumn("swversion").setHeaderCaption("SW Version");
+ grid.getColumn("responseStatus").setHeaderCaption("Response Update Status");
+ grid.getColumn("progress").setRenderer(new ProgressBarRenderer());
+ grid.getColumn("protocol").setConverter(new Converter() {
+ @Override
+ public Protocol convertToModel(final String value, final Class extends Protocol> targetType,
+ final Locale locale) {
+ return null;
+ }
+
+ @Override
+ public String convertToPresentation(final Protocol value, final Class extends String> targetType,
+ final Locale locale) {
+ switch (value) {
+ case DDI_HTTP:
+ return "DDI API (http)";
+ case DMF_AMQP:
+ return "DMF API (amqp)";
+ default:
+ return "unknown";
+ }
+ }
+
+ @Override
+ public Class getModelType() {
+ return Protocol.class;
+ }
+
+ @Override
+ public Class getPresentationType() {
+ return String.class;
+ }
+ });
+ grid.getColumn("status").setRenderer(new HtmlRenderer(), new Converter() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Status convertToModel(final String value, final Class extends Status> targetType,
+ final Locale locale) {
+ return null;
+ }
+
+ @Override
+ public String convertToPresentation(final Status value, final Class extends String> targetType,
+ final Locale locale) {
+ String style = null;
+ switch (value) {
+ case UNKNWON:
+ style = ""
+ + Integer.toHexString(FontAwesome.QUESTION_CIRCLE.getCodepoint()) + ";";
+ break;
+ case PEDNING:
+ style = "" + Integer.toHexString(FontAwesome.REFRESH.getCodepoint())
+ + ";";
+ break;
+ case FINISH:
+ style = ""
+ + Integer.toHexString(FontAwesome.CHECK_CIRCLE.getCodepoint()) + ";";
+ break;
+ case ERROR:
+ style = ""
+ + Integer.toHexString(FontAwesome.EXCLAMATION_CIRCLE.getCodepoint()) + ";";
+ break;
+ default:
+ throw new IllegalStateException("unknown value");
+ }
+ return style;
+ }
+
+ @Override
+ public Class getModelType() {
+ return Status.class;
+ }
+
+ @Override
+ public Class getPresentationType() {
+ return String.class;
+ }
+ });
+ grid.removeColumn("tenant");
+
+ // grid combobox
+ responseComboBox.setItemIcon(ResponseStatus.SUCCESSFUL, FontAwesome.CHECK_CIRCLE);
+ responseComboBox.setItemIcon(ResponseStatus.ERROR, FontAwesome.EXCLAMATION_CIRCLE);
+ responseComboBox.setNullSelectionAllowed(false);
+ responseComboBox.setValue(ResponseStatus.SUCCESSFUL);
+ responseComboBox.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(final ValueChangeEvent event) {
+ beanContainer.getItemIds().forEach(
+ itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus")
+ .setValue(event.getProperty().getValue()));
+ }
+ });
+
+ // add all components
+ addComponent(caption);
+ addComponent(toolbar);
+ addComponent(grid);
+
+ setExpandRatio(grid, 1.0F);
+
+ // load beans
+ repository.getAll().forEach(device -> beanContainer.addBean(device));
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ eventbus.unregister(this);
+ }
+
+ @Subscribe
+ public void pollCounterUpdate(final NextPollCounterUpdate update) {
+ final List devices = update.getDevices();
+ this.getUI().access(new Runnable() {
+ @Override
+ public void run() {
+ devices.forEach(device -> {
+ final BeanItem item = beanContainer.getItem(device.getId());
+ if (item != null) {
+ item.getItemProperty("nextPollCounterSec").setValue(device.getNextPollCounterSec());
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Method to retrieve {@link InitUpdate} events from the event bus.
+ *
+ * @param update
+ * the update event posted on the event bus
+ */
+ @Subscribe
+ public void initUpdate(final InitUpdate update) {
+ final AbstractSimulatedDevice device = update.getDevice();
+ this.getUI().access(new Runnable() {
+ @Override
+ public void run() {
+ final BeanItem item = beanContainer.getItem(device.getId());
+ if (item != null) {
+ item.getItemProperty("progress").setValue(device.getProgress());
+ item.getItemProperty("status").setValue(Status.PEDNING);
+ item.getItemProperty("swversion").setValue(device.getSwversion());
+ }
+
+ }
+ });
+ }
+
+ /**
+ * Method to retrieve {@link ProgressUpdate} events from the event bus.
+ *
+ * @param update
+ * the update event posted on the event bus
+ */
+ @Subscribe
+ public void progessUpdate(final ProgressUpdate update) {
+ final AbstractSimulatedDevice device = update.getDevice();
+ this.getUI().access(new Runnable() {
+ @Override
+ public void run() {
+ final BeanItem item = beanContainer.getItem(device.getId());
+ if (item != null) {
+ item.getItemProperty("progress").setValue(device.getProgress());
+ if (device.getProgress() >= 1) {
+ switch (device.getResponseStatus()) {
+ case SUCCESSFUL:
+ item.getItemProperty("status").setValue(Status.FINISH);
+ break;
+ case ERROR:
+ item.getItemProperty("status").setValue(Status.ERROR);
+ break;
+ default:
+ item.getItemProperty("status").setValue(Status.UNKNWON);
+ }
+ } else {
+ item.getItemProperty("status").setValue(Status.PEDNING);
+ }
+ }
+
+ }
+ });
+ }
+
+ private void createToolbar() {
+ final Button createDevicesButton = new Button("generate...");
+ createDevicesButton.setIcon(FontAwesome.GEARS);
+ createDevicesButton.addClickListener(event -> openGenerateDialog());
+
+ final Button clearDevicesButton = new Button("clear");
+ clearDevicesButton.setIcon(FontAwesome.ERASER);
+ clearDevicesButton.addClickListener(event -> clearSimulatedDevices());
+
+ toolbar.addComponent(createDevicesButton);
+ toolbar.addComponent(clearDevicesButton);
+ toolbar.setSpacing(true);
+ }
+
+ private void clearSimulatedDevices() {
+ repository.clear();
+ beanContainer.removeAllItems();
+ }
+
+ private void openGenerateDialog() {
+ UI.getCurrent().addWindow(new GenerateDialog(new GenerateDialogCallback() {
+ @Override
+ public void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay,
+ final URL basePollUrl, final String gatewayToken, final Protocol protocol) {
+ for (int index = 0; index < amount; index++) {
+ final String deviceId = namePrefix + index;
+ beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId,
+ tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken)));
+ spSenderService.createOrUpdateThing(tenant, deviceId);
+ }
+ }
+ }));
+ }
+}
diff --git a/examples/hawkbit-device-simulator/src/main/resources/VAADIN/themes/simulator/styles.scss b/examples/hawkbit-device-simulator/src/main/resources/VAADIN/themes/simulator/styles.scss
new file mode 100644
index 000000000..56ed48c34
--- /dev/null
+++ b/examples/hawkbit-device-simulator/src/main/resources/VAADIN/themes/simulator/styles.scss
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+// Import valo after setting the parameters
+@import "../valo/valo";
+
+
+.simulator{
+ @include valo;
+
+ .yellowicon {
+ color: orange;
+ }
+ .greenicon {
+ color: green;
+ }
+ .grayicon {
+ color: gray;
+ }
+ .redicon {
+ color: red;
+ }
+
+ .v-grid-cell.centeralign {
+ text-align: center;
+ }
+}
\ No newline at end of file
diff --git a/examples/hawkbit-device-simulator/src/main/resources/application.properties b/examples/hawkbit-device-simulator/src/main/resources/application.properties
index 19dd2cb77..402f71bfe 100644
--- a/examples/hawkbit-device-simulator/src/main/resources/application.properties
+++ b/examples/hawkbit-device-simulator/src/main/resources/application.properties
@@ -25,7 +25,7 @@ spring.rabbitmq.virtualHost=/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.dynamic=true
-
+spring.rabbitmq.listener.prefetch=100
# SECURITY (SecurityProperties)
security.user.name=${BASIC_USERNAME:admin}
@@ -44,6 +44,6 @@ security.headers.frame=false
security.headers.content-type=false
security.headers.hsts=all
security.sessions=stateless
-security.ignored=
+security.ignored=/VAADIN/**
server.port=8083
diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetResource.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetResource.java
index 747432cd0..62c987ae8 100644
--- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetResource.java
+++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/api/client/DistributionSetResource.java
@@ -20,10 +20,11 @@ import feign.RequestLine;
/**
* Client binding for the Distribution resource of the management API.
*/
+@FunctionalInterface
public interface DistributionSetResource {
/**
- * Creates a list of distrbution sets.
+ * Creates a list of distribution sets.
*
* @param sets
* the request body java bean containing the necessary attributes
diff --git a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java
index 3f203f94f..02fb22725 100644
--- a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java
+++ b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java
@@ -51,7 +51,7 @@ public class MongoConfiguration extends AbstractMongoConfiguration {
@Autowired(required = false)
private MongoClientOptions options;
- private Mongo mongo;
+ private Mongo mongoConnection;
@Override
public String getDatabaseName() {
@@ -59,12 +59,12 @@ public class MongoConfiguration extends AbstractMongoConfiguration {
}
/**
- * Closes mongo client when destroyd.
+ * Closes mongo client when destroyed.
*/
@PreDestroy
public void close() {
- if (this.mongo != null) {
- this.mongo.close();
+ if (this.mongoConnection != null) {
+ this.mongoConnection.close();
}
}
@@ -76,14 +76,14 @@ public class MongoConfiguration extends AbstractMongoConfiguration {
if (properties.getPort() != null) {
LOG.debug("Create mongo by properties (host: {}, port: {})", uri.getHosts().get(0), properties.getPort());
- this.mongo = new MongoClient(Arrays.asList(new ServerAddress(uri.getHosts().get(0), properties.getPort())),
- uri.getOptions());
+ this.mongoConnection = new MongoClient(
+ Arrays.asList(new ServerAddress(uri.getHosts().get(0), properties.getPort())), uri.getOptions());
} else {
LOG.debug("Create mongo by URI : {}", uri);
- this.mongo = new MongoClient(uri);
+ this.mongoConnection = new MongoClient(uri);
}
- return this.mongo;
+ return this.mongoConnection;
}
/*
diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Action.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Action.java
index eb70f235b..80624054a 100644
--- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Action.java
+++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/Action.java
@@ -233,7 +233,7 @@ public class Action extends BaseEntity implements Comparable {
* checks if the {@link #forcedTime} is hit by the given
* {@code hitTimeMillis}, by means if the given milliseconds are greater
* than the forcedTime.
- *
+ *
* @param hitTimeMillis
* the milliseconds, mostly the
* {@link System#currentTimeMillis()}
@@ -274,7 +274,7 @@ public class Action extends BaseEntity implements Comparable {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#toString()
*/
@Override
@@ -284,11 +284,11 @@ public class Action extends BaseEntity implements Comparable {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#hashCode()
*/
@Override
- public int hashCode() {
+ public int hashCode() { // NOSONAR - as this is generated
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((actionType == null) ? 0 : actionType.hashCode());
@@ -301,12 +301,12 @@ public class Action extends BaseEntity implements Comparable {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) { // NOSONAR - as this is generated
- // code
+
if (this == obj) {
return true;
}
@@ -384,7 +384,7 @@ public class Action extends BaseEntity implements Comparable {
/**
* The action type for this action relation.
- *
+ *
*
*
*
diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java
index 3028be775..63a858a7d 100644
--- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java
+++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetTag.java
@@ -71,7 +71,7 @@ public class DistributionSetTag extends Tag {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#hashCode()
*/
@Override
@@ -84,11 +84,11 @@ public class DistributionSetTag extends Tag {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(final Object obj) { // NOSONAR - as this is generated
if (this == obj) {
return true;
}
diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java
index d6664ac59..35e0c4e99 100644
--- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java
+++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifact.java
@@ -129,11 +129,11 @@ public class ExternalArtifact extends Artifact {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#hashCode()
*/
@Override
- public int hashCode() {
+ public int hashCode() { // NOSONAR - as this is generated
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.getClass().getName().hashCode();
@@ -142,11 +142,11 @@ public class ExternalArtifact extends Artifact {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(final Object obj) { // NOSONAR - as this is generated
if (this == obj) {
return true;
}
diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java
index f6ed40e79..56d92c8e1 100644
--- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java
+++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/ExternalArtifactProvider.java
@@ -92,11 +92,11 @@ public class ExternalArtifactProvider extends NamedEntity {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#hashCode()
*/
@Override
- public int hashCode() {
+ public int hashCode() { // NOSONAR - as this is generated
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.getClass().getName().hashCode();
@@ -105,11 +105,11 @@ public class ExternalArtifactProvider extends NamedEntity {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(final Object obj) { // NOSONAR - as this is generated
if (this == obj) {
return true;
}
diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java
index a5ad493b9..baa4ee1f0 100644
--- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java
+++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/LocalArtifact.java
@@ -75,11 +75,11 @@ public class LocalArtifact extends Artifact {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#hashCode()
*/
@Override
- public int hashCode() {
+ public int hashCode() { // NOSONAR - as this is generated
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.getClass().getName().hashCode();
@@ -88,11 +88,11 @@ public class LocalArtifact extends Artifact {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(final Object obj) { // NOSONAR - as this is generated
if (this == obj) {
return true;
}
diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java
index a3685df66..49e73f749 100644
--- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java
+++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModule.java
@@ -257,7 +257,7 @@ public class SoftwareModule extends NamedVersionedEntity {
* @see java.lang.Object#hashCode()
*/
@Override
- public int hashCode() {
+ public int hashCode() { // NOSONAR - as this is generated
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.getClass().getName().hashCode();
@@ -270,7 +270,7 @@ public class SoftwareModule extends NamedVersionedEntity {
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(final Object obj) { // NOSONAR - as this is generated
if (this == obj) {
return true;
}
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/push/AsyncVaadinServletConfiguration.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/push/AsyncVaadinServletConfiguration.java
index 6eb6761e6..89ff3413e 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/push/AsyncVaadinServletConfiguration.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/push/AsyncVaadinServletConfiguration.java
@@ -32,6 +32,7 @@ import com.vaadin.spring.boot.internal.VaadinServletConfigurationProperties;
@Import(VaadinServletConfiguration.class)
public class AsyncVaadinServletConfiguration extends VaadinServletConfiguration {
+ @Override
@Bean
protected ServletRegistrationBean vaadinServletRegistration() {
return createServletRegistrationBean();
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java
index 9b29c780a..ff350511a 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/CustomFile.java
@@ -72,7 +72,7 @@ public class CustomFile implements Serializable {
/**
* Initialize details.
- *
+ *
* @param fileName
* uploaded file name
* @param baseSoftwareModuleName
@@ -138,7 +138,7 @@ public class CustomFile implements Serializable {
}
/**
- *
+ *
* @return the isValid
*/
public Boolean getIsValid() {
@@ -170,11 +170,11 @@ public class CustomFile implements Serializable {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#hashCode()
*/
@Override
- public int hashCode() {
+ public int hashCode() { // NOSONAR - as this is generated
final int prime = 31;
int result = 1;
result = prime * result + (fileName == null ? 0 : fileName.hashCode());
@@ -183,7 +183,7 @@ public class CustomFile implements Serializable {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java
index fa7130d23..f3b68bce6 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java
@@ -8,9 +8,6 @@
*/
package org.eclipse.hawkbit.ui.management.dstable;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -39,8 +36,6 @@ import com.google.common.base.Strings;
* Simple implementation of generics bean query which dynamically loads a batch
* of beans.
*
- *
- *
*/
public class DistributionBeanQuery extends AbstractBeanQuery {
@@ -55,7 +50,7 @@ public class DistributionBeanQuery extends AbstractBeanQuery
/**
* Bean query for retrieving beans/objects of type.
- *
+ *
* @param definition
* query definition
* @param queryConfig
@@ -92,8 +87,9 @@ public class DistributionBeanQuery extends AbstractBeanQuery
/**
* Load all the Distribution set.
- *
- * @parm startIndex as page start
+ *
+ * @param startIndex
+ * as page start
* @param count
* as total data
*/
@@ -193,15 +189,4 @@ public class DistributionBeanQuery extends AbstractBeanQuery
return distributionSetManagement;
}
- private void writeObject(final ObjectOutputStream out) throws IOException {
- out.defaultWriteObject();
- out.writeObject(firstPageDistributionSets);
- }
-
- @SuppressWarnings("unchecked")
- private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
- in.defaultReadObject();
- firstPageDistributionSets = (Page) in.readObject();
- }
-
}
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java
index 8ba60ec51..fa4022a3e 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java
@@ -14,6 +14,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
@@ -62,15 +63,13 @@ import com.vaadin.ui.Upload.SucceededListener;
/**
* Bulk target upload handler.
- *
- *
*
*/
public class BulkUploadHandler extends CustomComponent
implements SucceededListener, FailedListener, Receiver, StartedListener {
/**
- * *
+ *
*/
private static final long serialVersionUID = -1273494705754674501L;
private static final Logger LOG = LoggerFactory.getLogger(BulkUploadHandler.class);
@@ -103,7 +102,7 @@ public class BulkUploadHandler extends CustomComponent
final TargetBulkUpdateWindowLayout targetBulkUpdateWindowLayout;
/**
- *
+ *
* @param targetBulkUpdateWindowLayout
* @param targetManagement
* @param managementUIState
@@ -152,7 +151,7 @@ public class BulkUploadHandler extends CustomComponent
/*
* (non-Javadoc)
- *
+ *
* @see com.vaadin.ui.Upload.Receiver#receiveUpload(java.lang.String,
* java.lang.String)
*/
@@ -173,7 +172,7 @@ public class BulkUploadHandler extends CustomComponent
/*
* (non-Javadoc)
- *
+ *
* @see
* com.vaadin.ui.Upload.FailedListener#uploadFailed(com.vaadin.ui.Upload.
* FailedEvent)
@@ -185,7 +184,7 @@ public class BulkUploadHandler extends CustomComponent
/*
* (non-Javadoc)
- *
+ *
* @see
* com.vaadin.ui.Upload.SucceededListener#uploadSucceeded(com.vaadin.ui.
* Upload.SucceededEvent)
@@ -199,7 +198,7 @@ public class BulkUploadHandler extends CustomComponent
final SucceededEvent event;
/**
- *
+ *
* @param event
*/
public UploadAsync(final SucceededEvent event) {
@@ -208,15 +207,18 @@ public class BulkUploadHandler extends CustomComponent
@Override
public void run() {
- BufferedReader reader = null;
long innerCounter = 0;
String line;
- if (tempFile != null) {
- try {
+ if (tempFile == null) {
+ return;
+ }
+
+ try (InputStream tempStream = new FileInputStream(tempFile)) {
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(tempStream, Charset.defaultCharset()))) {
LOG.info("Bulk file upload started");
final double totalFileSize = getTotalNumberOfLines();
- reader = new BufferedReader(
- new InputStreamReader(new FileInputStream(tempFile), Charset.defaultCharset()));
+
/**
* Once control is in upload succeeded method automatically
* upload button is re-enabled. To disable the button firing
@@ -232,21 +234,16 @@ public class BulkUploadHandler extends CustomComponent
// Clearing after assignments are done
managementUIState.getTargetTableFilters().getBulkUpload().getTargetsCreated().clear();
- } catch (final FileNotFoundException e) {
- LOG.error("File not found with name {}", tempFile.getName(), e);
} catch (final IOException e) {
LOG.error("Error reading file {}", tempFile.getName(), e);
} finally {
- try {
- if (null != reader) {
- reader.close();
- resetCounts();
- deleteFile();
- }
- } catch (final IOException e) {
- LOG.error("Error while reading file ", e);
- }
+ resetCounts();
+ deleteFile();
}
+ } catch (final FileNotFoundException e) {
+ LOG.error("Temporary file not found with name {}", tempFile.getName(), e);
+ } catch (final IOException e) {
+ LOG.error("Error while opening temorary file ", e);
}
}
@@ -307,24 +304,19 @@ public class BulkUploadHandler extends CustomComponent
}
private double getTotalNumberOfLines() {
- InputStreamReader inputStreamReader;
- BufferedReader readerForSize = null;
+
double totalFileSize = 0;
- try {
- inputStreamReader = new InputStreamReader(new FileInputStream(tempFile), Charset.defaultCharset());
- readerForSize = new BufferedReader(inputStreamReader);
- totalFileSize = readerForSize.lines().count();
+ try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(tempFile),
+ Charset.defaultCharset())) {
+ try (BufferedReader readerForSize = new BufferedReader(inputStreamReader)) {
+ totalFileSize = readerForSize.lines().count();
+ }
} catch (final FileNotFoundException e) {
LOG.error("Error reading file {}", tempFile.getName(), e);
- } finally {
- if (readerForSize != null) {
- try {
- readerForSize.close();
- } catch (final IOException e) {
- LOG.error("Error while closing reader of file {}", tempFile.getName(), e);
- }
- }
+ } catch (final IOException e) {
+ LOG.error("Error while closing reader of file {}", tempFile.getName(), e);
}
+
return totalFileSize;
}
@@ -449,7 +441,7 @@ public class BulkUploadHandler extends CustomComponent
private static class NullOutputStream extends OutputStream {
/**
* null output stream.
- *
+ *
* @param i
* byte
*/
@@ -468,7 +460,7 @@ public class BulkUploadHandler extends CustomComponent
/*
* (non-Javadoc)
- *
+ *
* @see
* com.vaadin.ui.Upload.StartedListener#uploadStarted(com.vaadin.ui.Upload
* .StartedEvent)