diff --git a/README.md b/README.md
index a99cb2a51..95cacbc9f 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ mvn install
# Run and use
-We are not providing an off the shelf production ready hawkBit server. However, we recommend to check out the [Example Application](examples/hawkbit-example-app) for a runtime ready Spring Boot based server that is empowered by hawkBit.
+We are not providing an off the shelf production ready hawkBit server. However, we recommend to check out the [Example Application](examples/hawkbit-example-app) for a runtime ready Spring Boot based update server that is empowered by hawkBit.
# Releases and Roadmap
@@ -20,8 +20,8 @@ We are not providing an off the shelf production ready hawkBit server. However,
* The master branch contains future development towards 0.2. We are currently focusing on:
* Rollout Management for large scale rollouts.
* Clustering capabilities for the update server.
- * Upgrade of Spring Boot and Vaadin.
- * And of course tones of usability improvements and bug fixes.
+ * Upgrade of Spring Boot and Vaadin depedencies.
+ * And of course tons of usability improvements and bug fixes.
## Try out examples
@@ -42,7 +42,7 @@ We are not providing an off the shelf production ready hawkBit server. However,
`hawkbit-http-security` : implementation for security filters for HTTP.
`hawkbit-rest-api` : API classes for the REST Management API.
`hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API.
-`hawkbit-rest-resource` : Vaadin UI.
+`hawkbit-ui` : Vaadin UI.
`hawkbit-cache-redis` : spring cache manager configuration and implementation with redis, distributed cache and distributed events.
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/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/ActionStatusFields.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/ActionStatusFields.java
index f1aa7a8e0..22fa42474 100644
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/ActionStatusFields.java
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/ActionStatusFields.java
@@ -17,10 +17,6 @@ package org.eclipse.hawkbit.repository;
*/
public enum ActionStatusFields implements FieldNameProvider {
- /**
- * The type field.
- */
- TYPE("type"),
/**
* The id field.
*/
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTest.java
index a3533b658..94fa8beca 100644
--- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTest.java
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/AbstractIntegrationTest.java
@@ -209,7 +209,7 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware {
/*
* (non-Javadoc)
- *
+ *
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
* springframework.core.env. Environment)
*/
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLActionFieldsTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLActionFieldsTest.java
new file mode 100644
index 000000000..71cf511ae
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLActionFieldsTest.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.repository.ActionFields;
+import org.eclipse.hawkbit.repository.model.Action;
+import org.eclipse.hawkbit.repository.model.Action.ActionType;
+import org.eclipse.hawkbit.repository.model.Target;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.jpa.domain.Specification;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter actions")
+public class RSQLActionFieldsTest extends AbstractIntegrationTest {
+
+ private Target target;
+ private Action action;
+
+ @Before
+ public void setupBeforeTest() {
+ target = new Target("targetId123");
+ target.setDescription("targetId123");
+ targetManagement.createTarget(target);
+ action = new Action();
+ action.setActionType(ActionType.SOFT);
+ target.getActions().add(action);
+ action.setTarget(target);
+ actionRepository.save(action);
+ for (int i = 0; i < 10; i++) {
+ final Action newAction = new Action();
+ newAction.setActionType(ActionType.SOFT);
+ newAction.setActive(i % 2 == 0);
+ newAction.setTarget(target);
+ actionRepository.save(newAction);
+ target.getActions().add(newAction);
+ }
+
+ }
+
+ @Test
+ @Description("Test filter action by id")
+ public void testFilterByParameterId() {
+ assertRSQLQuery(ActionFields.ID.name() + "==" + action.getId(), 1);
+ assertRSQLQuery(ActionFields.ID.name() + "==noExist*", 0);
+ assertRSQLQuery(ActionFields.ID.name() + "=in=(" + action.getId() + ",1000000)", 1);
+ assertRSQLQuery(ActionFields.ID.name() + "=out=(" + action.getId() + ",1000000)", 10);
+ }
+
+ @Test
+ @Description("Test action by status")
+ public void testFilterByParameterStatus() {
+ assertRSQLQuery(ActionFields.STATUS.name() + "==pending", 5);
+ assertRSQLQuery(ActionFields.STATUS.name() + "=in=(pending)", 5);
+ assertRSQLQuery(ActionFields.STATUS.name() + "=out=(pending)", 6);
+
+ try {
+ assertRSQLQuery(ActionFields.STATUS.name() + "==true", 5);
+ fail();
+ } catch (final RSQLParameterUnsupportedFieldException e) {
+ }
+ }
+
+ private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
+
+ final Specification parse = RSQLUtility.parse(rsqlParam, ActionFields.class);
+ final Slice findEnitity = deploymentManagement.findActionsByTarget(parse, target,
+ new PageRequest(0, 100));
+ final long countAllEntities = deploymentManagement.countActionsByTarget(parse, target);
+ assertThat(findEnitity).isNotNull();
+ assertThat(countAllEntities).isEqualTo(expectedEntities);
+ }
+}
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetFieldTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetFieldTest.java
new file mode 100644
index 000000000..014b7a055
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetFieldTest.java
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import java.util.Arrays;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.TestDataUtil;
+import org.eclipse.hawkbit.repository.DistributionSetFields;
+import org.eclipse.hawkbit.repository.model.DistributionSet;
+import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
+import org.eclipse.hawkbit.repository.model.DistributionSetTag;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter distribution set")
+public class RSQLDistributionSetFieldTest extends AbstractIntegrationTest {
+
+ @Before
+ public void seuptBeforeTest() {
+
+ final DistributionSet ds = TestDataUtil.generateDistributionSet("DS", softwareManagement,
+ distributionSetManagement);
+ ds.setDescription("DS");
+ ds.getMetadata().add(new DistributionSetMetadata("metaKey", ds, "metaValue"));
+ distributionSetManagement.updateDistributionSet(ds);
+
+ final DistributionSet ds2 = TestDataUtil
+ .generateDistributionSets("NewDS", 3, softwareManagement, distributionSetManagement).get(0);
+
+ ds2.setDescription("DS2");
+ ds2.getMetadata().add(new DistributionSetMetadata("metaKey", ds2, "value"));
+ distributionSetManagement.updateDistributionSet(ds2);
+
+ final DistributionSetTag targetTag = tagManagement.createDistributionSetTag(new DistributionSetTag("Tag1"));
+ tagManagement.createDistributionSetTag(new DistributionSetTag("Tag2"));
+ tagManagement.createDistributionSetTag(new DistributionSetTag("Tag3"));
+ tagManagement.createDistributionSetTag(new DistributionSetTag("Tag4"));
+
+ distributionSetManagement.assignTag(Arrays.asList(ds.getId(), ds2.getId()), targetTag);
+ }
+
+ @Test
+ @Description("Test filter distribution set by id")
+ public void testFilterByParameterId() {
+ assertRSQLQuery(DistributionSetFields.ID.name() + "==*", 4);
+ }
+
+ @Test
+ @Description("Test filter distribution set by name")
+ public void testFilterByParameterName() {
+ assertRSQLQuery(DistributionSetFields.NAME.name() + "==DS", 1);
+ assertRSQLQuery(DistributionSetFields.NAME.name() + "==*DS", 4);
+ assertRSQLQuery(DistributionSetFields.NAME.name() + "==noExist*", 0);
+ assertRSQLQuery(DistributionSetFields.NAME.name() + "=in=(DS,notexist)", 1);
+ assertRSQLQuery(DistributionSetFields.NAME.name() + "=out=(DS,notexist)", 3);
+ }
+
+ @Test
+ @Description("Test filter distribution set by description")
+ public void testFilterByParameterDescription() {
+ assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS", 1);
+ assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS*", 2);
+ assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==noExist*", 0);
+ assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=in=(DS,notexist)", 1);
+ assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=out=(DS,notexist)", 3);
+ }
+
+ @Test
+ @Description("Test filter distribution set by version")
+ public void testFilterByParameterVersion() {
+ assertRSQLQuery(DistributionSetFields.VERSION.name() + "==v1.0", 2);
+ assertRSQLQuery(DistributionSetFields.VERSION.name() + "!=v1.0", 2);
+ assertRSQLQuery(DistributionSetFields.VERSION.name() + "=in=(v1.0,v1.1)", 3);
+ assertRSQLQuery(DistributionSetFields.VERSION.name() + "=out=(v1.0,error)", 2);
+ }
+
+ @Test
+ @Description("Test filter distribution set by complete property")
+ public void testFilterByAttribute() {
+ assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "==true", 4);
+ assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "==noExist*", 0);
+ assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "=in=(true)", 4);
+ assertRSQLQuery(DistributionSetFields.COMPLETE.name() + "=out=(true)", 0);
+ }
+
+ @Test
+ @Description("Test filter distribution set by tag")
+ public void testFilterByTag() {
+ assertRSQLQuery(DistributionSetFields.TAG.name() + "==Tag1", 2);
+ assertRSQLQuery(DistributionSetFields.TAG.name() + "==T*", 2);
+ assertRSQLQuery(DistributionSetFields.TAG.name() + "==noExist*", 0);
+ assertRSQLQuery(DistributionSetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
+ assertRSQLQuery(DistributionSetFields.TAG.name() + "=out=(Tag1,notexist)", 0);
+ }
+
+ @Test
+ @Description("Test filter distribution set by type")
+ public void testFilterByType() {
+ assertRSQLQuery(DistributionSetFields.TYPE.name() + "==ecl_os_app_jvm", 4);
+ assertRSQLQuery(DistributionSetFields.TYPE.name() + "==noExist*", 0);
+ assertRSQLQuery(DistributionSetFields.TYPE.name() + "=in=(ecl_os_app_jvm,ecl)", 4);
+ assertRSQLQuery(DistributionSetFields.TYPE.name() + "=out=(ecl_os_app_jvm)", 0);
+ }
+
+ @Test
+ @Description("")
+ public void testFilterByMetadata() {
+ assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==metaValue", 1);
+ assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==*v*", 2);
+ assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==noExist*", 0);
+ assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
+ assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
+ assertRSQLQuery(DistributionSetFields.METADATA.name() + ".notExist==metaValue", 0);
+
+ }
+
+ private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) {
+ final Page find = distributionSetManagement.findDistributionSetsAll(
+ RSQLUtility.parse(rsqlParam, DistributionSetFields.class), new PageRequest(0, 100), false);
+ final long countAll = find.getTotalElements();
+ assertThat(find).isNotNull();
+ assertThat(countAll).isEqualTo(excpectedEntity);
+ }
+}
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetMetadataFieldsTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetMetadataFieldsTest.java
new file mode 100644
index 000000000..2d113a0a3
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLDistributionSetMetadataFieldsTest.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.TestDataUtil;
+import org.eclipse.hawkbit.repository.DistributionSetMetadataFields;
+import org.eclipse.hawkbit.repository.model.DistributionSet;
+import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter distribution set metadata")
+public class RSQLDistributionSetMetadataFieldsTest extends AbstractIntegrationTest {
+
+ private Long distributionSetId;
+
+ @Before
+ public void setupBeforeTest() {
+ final DistributionSet distributionSet = TestDataUtil.generateDistributionSet("DS", softwareManagement,
+ distributionSetManagement);
+ distributionSetId = distributionSet.getId();
+ for (int i = 0; i < 5; i++) {
+ final DistributionSetMetadata distributionSetMetadata = new DistributionSetMetadata("" + i, distributionSet,
+ "" + i);
+ distributionSet.getMetadata().add(distributionSetMetadata);
+ }
+
+ distributionSetManagement.updateDistributionSet(distributionSet);
+ }
+
+ @Test
+ @Description("Test filter distribution set metadata by key")
+ public void testFilterByParameterKey() {
+ assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "==1", 1);
+ assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "!=1", 4);
+ assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "=in=(1,2)", 2);
+ assertRSQLQuery(DistributionSetMetadataFields.KEY.name() + "=out=(1,2)", 3);
+ }
+
+ @Test
+ @Description("Test filter distribution set metadata by value")
+ public void testFilterByParameterValue() {
+ assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "==1", 1);
+ assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=1", 4);
+ assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=in=(1,2)", 2);
+ assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=out=(1,2)", 3);
+ }
+
+ private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
+
+ final Page findEnitity = distributionSetManagement
+ .findDistributionSetMetadataByDistributionSetId(distributionSetId,
+ RSQLUtility.parse(rsqlParam, DistributionSetMetadataFields.class), new PageRequest(0, 100));
+ final long countAllEntities = findEnitity.getTotalElements();
+ assertThat(findEnitity).isNotNull();
+ assertThat(countAllEntities).isEqualTo(expectedEntities);
+ }
+}
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleFieldTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleFieldTest.java
new file mode 100644
index 000000000..8f2fba6da
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleFieldTest.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.repository.SoftwareModuleFields;
+import org.eclipse.hawkbit.repository.model.SoftwareModule;
+import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter software module")
+public class RSQLSoftwareModuleFieldTest extends AbstractIntegrationTest {
+
+ @Before
+ public void seuptBeforeTest() {
+
+ final SoftwareModule ah = softwareManagement
+ .createSoftwareModule(new SoftwareModule(appType, "agent-hub", "1.0.1", "agent-hub", ""));
+ softwareManagement.createSoftwareModule(new SoftwareModule(runtimeType, "oracle-jre", "1.7.2", "aa", ""));
+ softwareManagement.createSoftwareModule(new SoftwareModule(osType, "poky", "3.0.2", "aa", ""));
+
+ final SoftwareModule ah2 = softwareManagement
+ .createSoftwareModule(new SoftwareModule(appType, "agent-hub2", "1.0.1", "agent-hub2", ""));
+
+ final SoftwareModuleMetadata softwareModuleMetadata = new SoftwareModuleMetadata("metaKey", ah, "metaValue");
+ softwareManagement.createSoftwareModuleMetadata(softwareModuleMetadata);
+ ah.getMetadata().add(softwareModuleMetadata);
+ softwareManagement.updateSoftwareModule(ah);
+
+ final SoftwareModuleMetadata softwareModuleMetadata2 = new SoftwareModuleMetadata("metaKey", ah2, "value");
+ softwareManagement.createSoftwareModuleMetadata(softwareModuleMetadata2);
+ ah2.getMetadata().add(softwareModuleMetadata2);
+ softwareManagement.updateSoftwareModule(ah2);
+
+ }
+
+ @Test
+ @Description("Test filter software module by id")
+ public void testFilterByParameterId() {
+ assertRSQLQuery(SoftwareModuleFields.ID.name() + "==*", 4);
+ }
+
+ @Test
+ @Description("Test filter software module by name")
+ public void testFilterByParameterName() {
+ assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==agent-hub", 1);
+ assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==agent-hub*", 2);
+ assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==noExist*", 0);
+ assertRSQLQuery(SoftwareModuleFields.NAME.name() + "=in=(agent-hub,notexist)", 1);
+ assertRSQLQuery(SoftwareModuleFields.NAME.name() + "=out=(agent-hub,notexist)", 3);
+ }
+
+ @Test
+ @Description("Test filter software module by description")
+ public void testFilterByParameterDescription() {
+ assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==agent-hub", 1);
+ assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==noExist*", 0);
+ assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=in=(agent-hub,notexist)", 1);
+ assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=out=(agent-hub,notexist)", 3);
+ }
+
+ @Test
+ @Description("Test filter software module by version")
+ public void testFilterByParameterVersion() {
+ assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "==1.0.1", 2);
+ assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "!=v1.0", 4);
+ assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "=in=(1.0.1,1.0.2)", 2);
+ assertRSQLQuery(SoftwareModuleFields.VERSION.name() + "=out=(1.0.1)", 2);
+ }
+
+ @Test
+ @Description("Test filter software module by type")
+ public void testFilterByType() {
+ assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "==application", 2);
+ assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "==noExist*", 0);
+ assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=in=(application)", 2);
+ assertRSQLQuery(SoftwareModuleFields.TYPE.name() + "=out=(application)", 2);
+ }
+
+ @Test
+ @Description("")
+ public void testFilterByMetadata() {
+ assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey==metaValue", 1);
+ assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey==*v*", 2);
+ assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey==noExist*", 0);
+ assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
+ assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
+ assertRSQLQuery(SoftwareModuleFields.METADATA.name() + ".notExist==metaValue", 0);
+
+ }
+
+ private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) {
+ final Page find = softwareManagement.findSoftwareModulesByPredicate(
+ RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class), new PageRequest(0, 100));
+ final long countAll = find.getTotalElements();
+ assertThat(find).isNotNull();
+ assertThat(countAll).isEqualTo(excpectedEntity);
+ }
+}
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleMetadataFieldsTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleMetadataFieldsTest.java
new file mode 100644
index 000000000..f75893b43
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleMetadataFieldsTest.java
@@ -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.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.TestDataUtil;
+import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields;
+import org.eclipse.hawkbit.repository.model.SoftwareModule;
+import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter software module metadata")
+public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractIntegrationTest {
+
+ private Long softwareModuleId;
+
+ @Before
+ public void setupBeforeTest() {
+ final SoftwareModule softwareModule = softwareManagement.createSoftwareModule(
+ new SoftwareModule(TestDataUtil.findOrCreateSoftwareModuleType(softwareManagement, "application"),
+ "application", "1.0.0", "Desc", "vendor Limited, California"));
+ softwareModuleId = softwareModule.getId();
+
+ for (int i = 0; i < 5; i++) {
+ final SoftwareModuleMetadata metadata = new SoftwareModuleMetadata("" + i, softwareModule, "" + i);
+ softwareModule.getMetadata().add(metadata);
+ softwareModuleMetadataRepository.save(metadata);
+ }
+
+ softwareManagement.updateSoftwareModule(softwareModule);
+ }
+
+ @Test
+ @Description("Test filter software module metadata by key")
+ public void testFilterByParameterKey() {
+ assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "==1", 1);
+ assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "!=1", 4);
+ assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "=in=(1,2)", 2);
+ assertRSQLQuery(SoftwareModuleMetadataFields.KEY.name() + "=out=(1,2)", 3);
+ }
+
+ @Test
+ @Description("Test fitler software module metadata status by value")
+ public void testFilterByParameterValue() {
+ assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "==1", 1);
+ assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 4);
+ assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=in=(1,2)", 2);
+ assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 3);
+ }
+
+ private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
+
+ final Page findEnitity = softwareManagement
+ .findSoftwareModuleMetadataBySoftwareModuleId(softwareModuleId,
+ RSQLUtility.parse(rsqlParam, SoftwareModuleMetadataFields.class), new PageRequest(0, 100));
+ final long countAllEntities = findEnitity.getTotalElements();
+ assertThat(findEnitity).isNotNull();
+ assertThat(countAllEntities).isEqualTo(expectedEntities);
+ }
+}
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleTypeFieldsTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleTypeFieldsTest.java
new file mode 100644
index 000000000..008de9199
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLSoftwareModuleTypeFieldsTest.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
+import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
+import org.junit.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter software module test type")
+public class RSQLSoftwareModuleTypeFieldsTest extends AbstractIntegrationTest {
+
+ @Test
+ @Description("Test filter software module test type by id")
+ public void testFilterByParameterId() {
+ assertRSQLQuery(SoftwareModuleTypeFields.ID.name() + "==*", 3);
+ }
+
+ @Test
+ @Description("Test filter software module test type by name")
+ public void testFilterByParameterName() {
+ assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==ECL*", 3);
+ }
+
+ @Test
+ @Description("Test filter software module test type by description")
+ public void testFilterByParameterDescription() {
+ assertRSQLQuery(SoftwareModuleTypeFields.DESCRIPTION.name() + "==Updated*", 3);
+ assertRSQLQuery(SoftwareModuleTypeFields.DESCRIPTION.name() + "==noExist*", 0);
+ }
+
+ @Test
+ @Description("Test filter software module test type by key")
+ public void testFilterByParameterKey() {
+ assertRSQLQuery(SoftwareModuleTypeFields.KEY.name() + "==os", 1);
+ assertRSQLQuery(SoftwareModuleTypeFields.KEY.name() + "=in=(os)", 1);
+ assertRSQLQuery(SoftwareModuleTypeFields.KEY.name() + "=out=(os)", 2);
+ }
+
+ @Test
+ @Description("Test filter software module test type by max")
+ public void testFilterByMaxAssignment() {
+ assertRSQLQuery(SoftwareModuleTypeFields.MAX.name() + "==1", 3);
+ }
+
+ private void assertRSQLQuery(final String rsqlParam, final long excpectedEntity) {
+ final Page find = softwareManagement.findSoftwareModuleTypesByPredicate(
+ RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class), new PageRequest(0, 100));
+ final long countAll = find.getTotalElements();
+ assertThat(find).isNotNull();
+ assertThat(countAll).isEqualTo(excpectedEntity);
+ }
+}
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTagFieldsTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTagFieldsTest.java
new file mode 100644
index 000000000..e3ab8fc2c
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTagFieldsTest.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.repository.TagFields;
+import org.eclipse.hawkbit.repository.model.DistributionSetTag;
+import org.eclipse.hawkbit.repository.model.TargetTag;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter target and distribution set tags")
+public class RSQLTagFieldsTest extends AbstractIntegrationTest {
+
+ @Before
+ public void seuptBeforeTest() {
+
+ for (int i = 0; i < 5; i++) {
+ final TargetTag targetTag = new TargetTag("" + i, "" + i, i % 2 == 0 ? "red" : "blue");
+ tagManagement.createTargetTag(targetTag);
+ final DistributionSetTag distributionSetTag = new DistributionSetTag("" + i, "" + i,
+ i % 2 == 0 ? "red" : "blue");
+ tagManagement.createDistributionSetTag(distributionSetTag);
+ }
+ }
+
+ @Test
+ @Description("Test filter target tag by name")
+ public void testFilterTargetTagByParameterName() {
+ assertRSQLQueryTarget(TagFields.NAME.name() + "==1", 1);
+ assertRSQLQueryTarget(TagFields.NAME.name() + "==*", 5);
+ assertRSQLQueryTarget(TagFields.NAME.name() + "==noExist*", 0);
+ assertRSQLQueryTarget(TagFields.NAME.name() + "=in=(1,notexist)", 1);
+ assertRSQLQueryTarget(TagFields.NAME.name() + "=out=(1,notexist)", 4);
+ }
+
+ @Test
+ @Description("Test filter target tag by description")
+ public void testFilterTargetTagByParameterDescription() {
+ assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "==1", 1);
+ assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "==*", 5);
+ assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "==noExist*", 0);
+ assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "=in=(1,notexist)", 1);
+ assertRSQLQueryTarget(TagFields.DESCRIPTION.name() + "=out=(1,notexist)", 4);
+ }
+
+ @Test
+ @Description("Test filter target tag by colour")
+ public void testFilterTargetTagByParameterColour() {
+ assertRSQLQueryTarget(TagFields.COLOUR.name() + "==red", 3);
+ assertRSQLQueryTarget(TagFields.COLOUR.name() + "==r*", 3);
+ assertRSQLQueryTarget(TagFields.COLOUR.name() + "==noExist*", 0);
+ assertRSQLQueryTarget(TagFields.COLOUR.name() + "=in=(red,notexist)", 3);
+ assertRSQLQueryTarget(TagFields.COLOUR.name() + "=out=(red,notexist)", 2);
+ }
+
+ @Test
+ @Description("Test filter distribution set tag by name")
+ public void testFilterDistributionSetTagByParameterName() {
+ assertRSQLQueryDistributionSet(TagFields.NAME.name() + "==1", 1);
+ assertRSQLQueryDistributionSet(TagFields.NAME.name() + "==*", 5);
+ assertRSQLQueryDistributionSet(TagFields.NAME.name() + "==noExist*", 0);
+ assertRSQLQueryDistributionSet(TagFields.NAME.name() + "=in=(1,2)", 2);
+ assertRSQLQueryDistributionSet(TagFields.NAME.name() + "=out=(1,2)", 3);
+ }
+
+ @Test
+ @Description("Test filter distribution set by description")
+ public void testFilterDistributionSetTagByParameterDescription() {
+ assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "==1", 1);
+ assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "==*", 5);
+ assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "==noExist*", 0);
+ assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "=in=(1,2)", 2);
+ assertRSQLQueryDistributionSet(TagFields.DESCRIPTION.name() + "=out=(1,2)", 3);
+ }
+
+ @Test
+ @Description("Test filter distribution set by colour")
+ public void testFilterDistributionSetTagByParameterColour() {
+ assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "==red", 3);
+ assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "==r*", 3);
+ assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "==noExist*", 0);
+ assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "=in=(red,notexist)", 3);
+ assertRSQLQueryDistributionSet(TagFields.COLOUR.name() + "=out=(red,notexist)", 2);
+ }
+
+ private void assertRSQLQueryDistributionSet(final String rsqlParam, final long expectedEntities) {
+
+ final Page findEnitity = tagManagement
+ .findAllDistributionSetTags(RSQLUtility.parse(rsqlParam, TagFields.class), new PageRequest(0, 100));
+ final long countAllEntities = findEnitity.getTotalElements();
+ assertThat(findEnitity).isNotNull();
+ assertThat(countAllEntities).isEqualTo(expectedEntities);
+ }
+
+ private void assertRSQLQueryTarget(final String rsqlParam, final long expectedEntities) {
+
+ final Page findEnitity = tagManagement
+ .findAllTargetTags(RSQLUtility.parse(rsqlParam, TagFields.class), new PageRequest(0, 100));
+ final long countAllEntities = findEnitity.getTotalElements();
+ assertThat(findEnitity).isNotNull();
+ assertThat(countAllEntities).isEqualTo(expectedEntities);
+ }
+}
diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java
new file mode 100644
index 000000000..50b6600e9
--- /dev/null
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLTargetFieldTest.java
@@ -0,0 +1,171 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.repository.rsql;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+
+import org.eclipse.hawkbit.AbstractIntegrationTest;
+import org.eclipse.hawkbit.TestDataUtil;
+import org.eclipse.hawkbit.repository.TargetFields;
+import org.eclipse.hawkbit.repository.model.DistributionSet;
+import org.eclipse.hawkbit.repository.model.Target;
+import org.eclipse.hawkbit.repository.model.TargetInfo;
+import org.eclipse.hawkbit.repository.model.TargetTag;
+import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import ru.yandex.qatools.allure.annotations.Description;
+import ru.yandex.qatools.allure.annotations.Features;
+import ru.yandex.qatools.allure.annotations.Stories;
+
+@Features("Component Tests - RSQL filtering")
+@Stories("RSQL filter target")
+public class RSQLTargetFieldTest extends AbstractIntegrationTest {
+
+ @Before
+ public void seuptBeforeTest() {
+
+ final DistributionSet ds = TestDataUtil.generateDistributionSet("AssignedDs", softwareManagement,
+ distributionSetManagement);
+
+ final Target target = new Target("targetId123");
+ target.setDescription("targetId123");
+ final TargetInfo targetInfo = new TargetInfo(target);
+ targetInfo.getControllerAttributes().put("revision", "1.1");
+ target.setTargetInfo(targetInfo);
+ target.getTargetInfo().setUpdateStatus(TargetUpdateStatus.PENDING);
+
+ targetManagement.createTarget(target);
+ final Target target2 = new Target("targetId1234");
+ target2.setDescription("targetId1234");
+ final TargetInfo targetInfo2 = new TargetInfo(target2);
+ targetInfo2.getControllerAttributes().put("revision", "1.2");
+ target2.setTargetInfo(targetInfo2);
+ targetManagement.createTarget(target2);
+ targetManagement.createTarget(new Target("targetId1235"));
+ targetManagement.createTarget(new Target("targetId1236"));
+
+ final TargetTag targetTag = tagManagement.createTargetTag(new TargetTag("Tag1"));
+ tagManagement.createTargetTag(new TargetTag("Tag2"));
+ tagManagement.createTargetTag(new TargetTag("Tag3"));
+ tagManagement.createTargetTag(new TargetTag("Tag4"));
+
+ targetManagement.assignTag(Arrays.asList(target.getControllerId(), target2.getControllerId()), targetTag);
+
+ deploymentManagement.assignDistributionSet(ds.getId(), target.getControllerId());
+ }
+
+ @Test
+ @Description("Test filter target by (controller) id")
+ public void testFilterByParameterId() {
+ assertRSQLQuery(TargetFields.ID.name() + "==targetId123", 1);
+ assertRSQLQuery(TargetFields.ID.name() + "==target*", 4);
+ assertRSQLQuery(TargetFields.ID.name() + "==noExist*", 0);
+ assertRSQLQuery(TargetFields.ID.name() + "=in=(targetId123,notexist)", 1);
+ assertRSQLQuery(TargetFields.ID.name() + "=out=(targetId123,notexist)", 3);
+ }
+
+ @Test
+ @Description("Test filter target by name")
+ public void testFilterByParameterName() {
+ assertRSQLQuery(TargetFields.NAME.name() + "==targetId123", 1);
+ assertRSQLQuery(TargetFields.NAME.name() + "==target*", 4);
+ assertRSQLQuery(TargetFields.NAME.name() + "==noExist*", 0);
+ assertRSQLQuery(TargetFields.NAME.name() + "=in=(targetId123,notexist)", 1);
+ assertRSQLQuery(TargetFields.NAME.name() + "=out=(targetId123,notexist)", 3);
+ }
+
+ @Test
+ @Description("Test filter target by description")
+ public void testFilterByParameterDescription() {
+ assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==targetId123", 1);
+ assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==target*", 2);
+ assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==noExist*", 0);
+ assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=in=(targetId123,notexist)", 1);
+ assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=out=(targetId123,notexist)", 1);
+ }
+
+ @Test
+ @Description("Test filter target by controller id")
+ public void testFilterByParameterControllerId() {
+ assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==targetId123", 1);
+ assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==target*", 4);
+ assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==noExist*", 0);
+ assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=in=(targetId123,notexist)", 1);
+ assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=out=(targetId123,notexist)", 3);
+ }
+
+ @Test
+ @Description("Test filter target by status")
+ public void testFilterByParameterUpdateStatus() {
+ assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "==pending", 1);
+ assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "!=pending", 3);
+ try {
+ assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "==noExist*", 0);
+ fail();
+ } catch (final RSQLParameterUnsupportedFieldException e) {
+ }
+ assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "=in=(pending,error)", 1);
+ assertRSQLQuery(TargetFields.UPDATESTATUS.name() + "=out=(pending,error)", 3);
+ }
+
+ @Test
+ @Description("Test filter target by attribute")
+ public void testFilterByAttribute() {
+ assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1.1", 1);
+ assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1*", 2);
+ assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==noExist*", 0);
+ assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=in=(1.1,notexist)", 1);
+ assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=out=(1.1)", 1);
+ }
+
+ @Test
+ @Description("Test filter target by assigned ds name")
+ public void testFilterByAssignedDsName() {
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==AssignedDs", 1);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==A*", 1);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==noExist*", 0);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=in=(AssignedDs,notexist)", 1);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=out=(AssignedDs,notexist)", 0);
+ }
+
+ @Test
+ @Description("Test filter target by assigned ds version")
+ public void testFilterByAssignedDsVersion() {
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==v1.0", 1);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==*1*", 1);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==noExist*", 0);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=in=(v1.0,notexist)", 1);
+ assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=out=(v1.0,notexist)", 0);
+ }
+
+ @Test
+ @Description("Test filter target by tag")
+ public void testFilterByTag() {
+ assertRSQLQuery(TargetFields.TAG.name() + "==Tag1", 2);
+ assertRSQLQuery(TargetFields.TAG.name() + "==T*", 2);
+ assertRSQLQuery(TargetFields.TAG.name() + "==noExist*", 0);
+ assertRSQLQuery(TargetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
+ assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 0);
+ }
+
+ private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) {
+ final Page findTargetPage = targetManagement
+ .findTargetsAll(RSQLUtility.parse(rsqlParam, TargetFields.class), new PageRequest(0, 100));
+ final long countTargetsAll = findTargetPage.getTotalElements();
+ assertThat(findTargetPage).isNotNull();
+ assertThat(countTargetsAll).isEqualTo(expcetedTargets);
+ }
+}
diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/RSQLUtilityTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLUtilityTest.java
similarity index 97%
rename from hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/RSQLUtilityTest.java
rename to hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLUtilityTest.java
index c23c52bc5..85092b560 100644
--- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/rest/resource/RSQLUtilityTest.java
+++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/rsql/RSQLUtilityTest.java
@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
-package org.eclipse.hawkbit.rest.resource;
+package org.eclipse.hawkbit.repository.rsql;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
@@ -31,9 +31,6 @@ import org.eclipse.hawkbit.repository.FieldNameProvider;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
-import org.eclipse.hawkbit.repository.rsql.RSQLParameterSyntaxException;
-import org.eclipse.hawkbit.repository.rsql.RSQLParameterUnsupportedFieldException;
-import org.eclipse.hawkbit.repository.rsql.RSQLUtility;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -43,7 +40,7 @@ import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@RunWith(MockitoJUnitRunner.class)
-@Features("Component Tests - Management RESTful API")
+@Features("Component Tests - RSQL filtering")
@Stories("RSQL search utility")
// TODO: fully document tests -> @Description for long text and reasonable
// method name as short text