diff --git a/hawkbit-device-simulator/.gitignore b/hawkbit-device-simulator/.gitignore
index 09e3bc9..cfb6698 100644
--- a/hawkbit-device-simulator/.gitignore
+++ b/hawkbit-device-simulator/.gitignore
@@ -1,2 +1,5 @@
/bin/
/target/
+/pom2.xml
+/pom3.xml
+/pom4.xml
diff --git a/hawkbit-device-simulator/README.md b/hawkbit-device-simulator/README.md
index a6cae6c..dbe9362 100644
--- a/hawkbit-device-simulator/README.md
+++ b/hawkbit-device-simulator/README.md
@@ -12,19 +12,6 @@ Or:
run org.eclipse.hawkbit.simulator.DeviceSimulator
```
-## Deploy to cloud foundry environment
-
-- Go to ```target``` subfolder.
-- Run ```cf push```
-
-## Notes
-
-The simulator has user authentication enabled in **cloud profile**. Default credentials:
-* username : admin
-* passwd : admin
-
-This can be configured/disabled by spring boot properties
-
## hawkBit APIs
The simulator supports `DDI` as well as the `DMF` integration APIs.
diff --git a/hawkbit-device-simulator/pom.xml b/hawkbit-device-simulator/pom.xml
index 0e97b58..a139442 100644
--- a/hawkbit-device-simulator/pom.xml
+++ b/hawkbit-device-simulator/pom.xml
@@ -104,11 +104,15 @@
org.springframework.cloud
- spring-cloud-commons
+ spring-cloud-context
org.springframework.cloud
- spring-cloud-context
+ spring-cloud-starter-openfeign
+
+
+ io.github.openfeign
+ feign-jackson
com.google.guava
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AllowAllWebSecurityConfig.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AllowAllWebSecurityConfig.java
new file mode 100644
index 0000000..6ee6204
--- /dev/null
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AllowAllWebSecurityConfig.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2019 Bosch Software Innovations GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.hawkbit.simulator;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+/**
+ * Spring security configuration to grant access for all incomming requests.
+ */
+@Configuration
+public class AllowAllWebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(final HttpSecurity httpSec) throws Exception {
+ httpSec.csrf().disable().authorizeRequests().antMatchers("/**").permitAll().anyRequest().authenticated();
+ }
+}
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java
index 67bc4da..e6024a4 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java
@@ -18,7 +18,7 @@
import org.eclipse.hawkbit.simulator.amqp.DmfSenderService;
import org.eclipse.hawkbit.simulator.http.GatewayTokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder;
+import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.stereotype.Service;
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java
index c660fe4..f4eb195 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java
@@ -8,17 +8,21 @@
*/
package org.eclipse.hawkbit.simulator;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Optional;
+
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.AmqpProperties;
+import org.eclipse.hawkbit.simulator.amqp.DmfSenderService;
+import org.eclipse.hawkbit.simulator.amqp.SimulatedUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
-import java.net.MalformedURLException;
-import java.net.URL;
-
/**
* REST endpoint for controlling the device simulator.
*/
@@ -33,8 +37,11 @@ public class SimulationController {
private final SimulationProperties simulationProperties;
+ private Optional spSenderService = Optional.empty();
+
@Autowired
- public SimulationController(final DeviceSimulatorRepository repository, final SimulatedDeviceFactory deviceFactory, final AmqpProperties amqpProperties, final SimulationProperties simulationProperties) {
+ public SimulationController(final DeviceSimulatorRepository repository, final SimulatedDeviceFactory deviceFactory,
+ final AmqpProperties amqpProperties, final SimulationProperties simulationProperties) {
this.repository = repository;
this.deviceFactory = deviceFactory;
this.amqpProperties = amqpProperties;
@@ -56,8 +63,7 @@ public SimulationController(final DeviceSimulatorRepository repository, final Si
* the URL endpoint to be used of the hawkbit-update-server for
* DDI devices
* @param pollDelay
- * number of delay in seconds to delay polling of DDI
- * devices
+ * number of delay in seconds to delay polling of DDI devices
* @param gatewayToken
* the hawkbit-update-server gatewaytoken in case authentication
* is enforced in hawkbit
@@ -87,9 +93,7 @@ ResponseEntity start(@RequestParam(value = "name", defaultValue = "simul
}
if (protocol == Protocol.DMF_AMQP && isDmfDisabled()) {
- return ResponseEntity.badRequest()
- .body("The AMQP interface has been disabled, to use DMF protocol you need to enable the AMQP interface via '"
- + AmqpProperties.CONFIGURATION_PREFIX + ".enabled=true'");
+ return createAmqpDisabledResponse();
}
for (int i = 0; i < amount; i++) {
@@ -102,11 +106,17 @@ ResponseEntity start(@RequestParam(value = "name", defaultValue = "simul
return ResponseEntity.ok("Updated " + amount + " " + protocol + " connected targets!");
}
+ private ResponseEntity createAmqpDisabledResponse() {
+ return ResponseEntity.badRequest().body(
+ "The AMQP interface has been disabled, to use DMF protocol you need to enable the AMQP interface via '"
+ + AmqpProperties.CONFIGURATION_PREFIX + ".enabled=true'");
+ }
+
/**
* Update an attribute of a device.
*
* NOTE: This represents not the expected client behaviour for DDI, since a
- * DDI client shall only update its attributes if requested by hawkBit.
+ * DDI client shall only update its attributes if requested by hawkBit.
*
* @param tenant
* The tenant the device belongs to
@@ -150,7 +160,7 @@ ResponseEntity update(@RequestParam(value = "tenant", required = false)
* if not found.
*/
@GetMapping("/remove")
- ResponseEntity remove(@RequestParam(value = "tenant", required = false) final String tenant,
+ ResponseEntity remove(@RequestParam(value = "tenant", required = false) final String tenant,
@RequestParam(value = "controllerid") final String controllerId) {
final AbstractSimulatedDevice controller = repository
@@ -176,6 +186,39 @@ ResponseEntity reset() {
return ResponseEntity.ok("All simulated devices have been removed.");
}
+ /**
+ * Report action as FINISHED Sends an UpdateActionStatus event with value
+ * FINISHED
+ *
+ * @return A response string that the action_finished event was sent
+ */
+ @GetMapping("/finishAction")
+ ResponseEntity finishAction(@RequestParam(value = "actionId") final long actionId,
+ @RequestParam(value = "tenant", required = false) final String tenant,
+ @RequestParam(value = "controllerId") final String controllerId) {
+
+ if (!spSenderService.isPresent()) {
+ return createAmqpDisabledResponse();
+ }
+
+ final String theTenant = tenant != null && !tenant.isEmpty() ? tenant : simulationProperties.getDefaultTenant();
+ final AbstractSimulatedDevice device = repository.get(theTenant, controllerId);
+
+ if (device == null) {
+ return ResponseEntity.notFound().build();
+ }
+
+ spSenderService.get().finishUpdateProcess(new SimulatedUpdate(device.getTenant(), device.getId(), actionId),
+ Collections.singletonList("Simulation Finished."));
+
+ return ResponseEntity.ok(String.format("Action with id: [%d] reported as FINISHED", actionId));
+ }
+
+ @Autowired(required = false)
+ public void setSpSenderService(final DmfSenderService spSenderService) {
+ this.spSenderService = Optional.of(spSenderService);
+ }
+
private boolean isDmfDisabled() {
return !amqpProperties.isEnabled();
}
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java
index 6088aa6..0687b33 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java
@@ -44,12 +44,12 @@ public UpdateStatus(final ResponseStatus responseStatus, final String message) {
}
/**
- * Constructor including status message.
+ * Constructor including status messages.
*
* @param responseStatus
* of the update
- * @param messages
- * of the update status
+ * @param statusMessages
+ * list of status messages
*/
public UpdateStatus(final ResponseStatus responseStatus, final List statusMessages) {
this(responseStatus);
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
index d235af0..3e8bbe6 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java
@@ -14,23 +14,19 @@
import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater;
import org.eclipse.hawkbit.simulator.SimulationProperties;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.retry.backoff.ExponentialBackOffPolicy;
-import org.springframework.retry.support.RetryTemplate;
import com.google.common.collect.Maps;
@@ -43,33 +39,6 @@
@ConditionalOnProperty(prefix = AmqpProperties.CONFIGURATION_PREFIX, name = "enabled")
public class AmqpConfiguration {
- private static final Logger LOGGER = LoggerFactory.getLogger(AmqpConfiguration.class);
-
- @Autowired
- private AmqpProperties amqpProperties;
-
- @Bean
- RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
- final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
- rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
-
- final RetryTemplate retryTemplate = new RetryTemplate();
- retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy());
- rabbitTemplate.setRetryTemplate(retryTemplate);
-
- rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
- if (ack) {
- LOGGER.debug("Message with correlation ID {} confirmed by broker.", correlationData.getId());
- } else {
- LOGGER.error("Broker is unable to handle message with correlation ID {} : {}", correlationData.getId(),
- cause);
- }
-
- });
-
- return rabbitTemplate;
- }
-
@Bean
DmfReceiverService dmfReceiverService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties,
final DmfSenderService spSenderService, final DeviceSimulatorUpdater deviceUpdater,
@@ -83,6 +52,21 @@ DmfSenderService dmfSenderService(final RabbitTemplate rabbitTemplate, final Amq
return new DmfSenderService(rabbitTemplate, amqpProperties, simulationProperties);
}
+ @Bean
+ public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
+ final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
+
+ // It is necessary to define rabbitTemplate as a Bean and set
+ // Jackson2JsonMessageConverter explicitly here in order to convert only
+ // OUTCOMING messages to json. In case of INCOMING messages,
+ // Jackson2JsonMessageConverter can not handle messages with NULL
+ // payload (e.g. REQUEST_ATTRIBUTES_UPDATE), so the
+ // SimpleMessageConverter is used instead per default.
+ rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
+
+ return rabbitTemplate;
+ }
+
/**
* Creates the receiver queue from update server for receiving message from
* update server.
@@ -90,11 +74,16 @@ DmfSenderService dmfSenderService(final RabbitTemplate rabbitTemplate, final Amq
* @return the queue
*/
@Bean
- Queue receiverConnectorQueueFromHawkBit() {
- final Map arguments = getTTLMaxArgs();
-
+ Queue receiverConnectorQueueFromHawkBit(final AmqpProperties amqpProperties) {
return QueueBuilder.nonDurable(amqpProperties.getReceiverConnectorQueueFromSp()).autoDelete()
- .withArguments(arguments).build();
+ .withArguments(getTTLMaxArgs()).build();
+ }
+
+ private static Map getTTLMaxArgs() {
+ final Map args = Maps.newHashMapWithExpectedSize(2);
+ args.put("x-message-ttl", Duration.ofDays(1).toMillis());
+ args.put("x-max-length", 100_000);
+ return args;
}
/**
@@ -103,7 +92,7 @@ Queue receiverConnectorQueueFromHawkBit() {
* @return the exchange
*/
@Bean
- FanoutExchange exchangeQueueToConnector() {
+ FanoutExchange exchangeQueueToConnector(final AmqpProperties amqpProperties) {
return new FanoutExchange(amqpProperties.getSenderForSpExchange(), false, true);
}
@@ -115,15 +104,18 @@ FanoutExchange exchangeQueueToConnector() {
* @return the binding and create the queue and exchange
*/
@Bean
- Binding bindReceiverQueueToSpExchange() {
- return BindingBuilder.bind(receiverConnectorQueueFromHawkBit()).to(exchangeQueueToConnector());
+ Binding bindReceiverQueueToSpExchange(final AmqpProperties amqpProperties) {
+ return BindingBuilder.bind(receiverConnectorQueueFromHawkBit(amqpProperties))
+ .to(exchangeQueueToConnector(amqpProperties));
}
- private static Map getTTLMaxArgs() {
- final Map args = Maps.newHashMapWithExpectedSize(2);
- args.put("x-message-ttl", Duration.ofDays(1).toMillis());
- args.put("x-max-length", 100_000);
- return args;
- }
+ @Configuration
+ @ConditionalOnProperty(prefix = AmqpProperties.CONFIGURATION_PREFIX, name = "customVhost")
+ protected static class CachingConnectionFactoryInitializer {
+ CachingConnectionFactoryInitializer(final CachingConnectionFactory connectionFactory,
+ final AmqpProperties amqpProperties) {
+ connectionFactory.setVirtualHost(amqpProperties.getCustomVhost());
+ }
+ }
}
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java
index 9bafd4f..1a0c246 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java
@@ -51,6 +51,8 @@ public class AmqpProperties {
*/
private int deadLetterTtl = 60_000;
+ private String customVhost;
+
public boolean isCheckDmfHealth() {
return checkDmfHealth;
}
@@ -90,4 +92,12 @@ public boolean isEnabled() {
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
+
+ public String getCustomVhost() {
+ return customVhost;
+ }
+
+ public void setCustomVhost(final String customVhost) {
+ this.customVhost = customVhost;
+ }
}
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfReceiverService.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfReceiverService.java
index 17c8193..0fa117d 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfReceiverService.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfReceiverService.java
@@ -10,6 +10,8 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -22,7 +24,6 @@
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
import org.eclipse.hawkbit.simulator.DeviceSimulatorUpdater;
-import org.eclipse.jetty.util.ConcurrentHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
@@ -47,7 +48,7 @@ public class DmfReceiverService extends MessageService {
private final DeviceSimulatorRepository repository;
- private final Set openPings = new ConcurrentHashSet<>();
+ private final Set openPings = Collections.synchronizedSet(new HashSet<>());
/**
* Constructor.
@@ -126,8 +127,7 @@ public void recieveMessageSp(final Message message, @Header(MessageHeaderKey.TYP
}
if (MessageType.PING_RESPONSE.equals(messageType)) {
- final String correlationId = new String(message.getMessageProperties().getCorrelationId(),
- StandardCharsets.UTF_8);
+ final String correlationId = message.getMessageProperties().getCorrelationId();
if (!openPings.remove(correlationId)) {
LOGGER.error("Unknown PING_RESPONSE received for correlationId: {}.", correlationId);
}
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfSenderService.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfSenderService.java
index 4c45354..eb62973 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfSenderService.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/DmfSenderService.java
@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
-import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -28,8 +27,8 @@
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
-import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.amqp.support.converter.AbstractJavaTypeMapper;
/**
@@ -63,7 +62,7 @@ public void ping(final String tenant, final String correlationId) {
final MessageProperties messageProperties = new MessageProperties();
messageProperties.getHeaders().put(MessageHeaderKey.TENANT, tenant);
messageProperties.getHeaders().put(MessageHeaderKey.TYPE, MessageType.PING.toString());
- messageProperties.setCorrelationId(correlationId.getBytes());
+ messageProperties.setCorrelationId(correlationId);
messageProperties.setReplyTo(amqpProperties.getSenderForSpExchange());
messageProperties.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN);
@@ -77,9 +76,6 @@ public void ping(final String tenant, final String correlationId) {
* the simulated update object
* @param updateResultMessages
* a description according the update process
- * @param actionType
- * indicating whether to download and install or skip
- * installation due to maintenance window.
*/
public void finishUpdateProcess(final SimulatedUpdate update, final List updateResultMessages) {
final Message updateResultMessage = createUpdateResultMessage(update, DmfActionStatus.FINISHED,
@@ -118,7 +114,7 @@ public void sendMessage(final String address, final Message message) {
final String correlationId = UUID.randomUUID().toString();
if (isCorrelationIdEmpty(message)) {
- message.getMessageProperties().setCorrelationId(correlationId.getBytes(StandardCharsets.UTF_8));
+ message.getMessageProperties().setCorrelationId(correlationId);
}
if (LOGGER.isTraceEnabled()) {
@@ -132,7 +128,7 @@ public void sendMessage(final String address, final Message message) {
private static boolean isCorrelationIdEmpty(final Message message) {
return message.getMessageProperties().getCorrelationId() == null
- || message.getMessageProperties().getCorrelationId().length <= 0;
+ || message.getMessageProperties().getCorrelationId().length() <= 0;
}
/**
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java
index d47ab59..10ba185 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java
@@ -35,8 +35,6 @@ public class MessageService {
* the rabbit template
* @param amqpProperties
* the amqp properties
- * @param messageConverter
- * the message converter
*/
public MessageService(final RabbitTemplate rabbitTemplate, final AmqpProperties amqpProperties) {
this.rabbitTemplate = rabbitTemplate;
diff --git a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SimulatedUpdate.java b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SimulatedUpdate.java
index 3c46e89..6aaa700 100644
--- a/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SimulatedUpdate.java
+++ b/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SimulatedUpdate.java
@@ -24,7 +24,15 @@ public class SimulatedUpdate implements Serializable {
private final Long actionId;
private transient LocalDateTime startCacheTime;
- SimulatedUpdate(final String tenant, final String thingId, final Long actionId) {
+ /**
+ * @param tenant
+ * the tenant for this thing and for this simulated update
+ * @param thingId
+ * the thing id that this simulated update correlates to
+ * @param actionId
+ * the id of the action related to this simulated update
+ */
+ public SimulatedUpdate(final String tenant, final String thingId, final Long actionId) {
this.tenant = tenant;
this.thingId = thingId;
this.actionId = actionId;
diff --git a/hawkbit-device-simulator/src/main/resources/application.properties b/hawkbit-device-simulator/src/main/resources/application.properties
index b7a0588..addd4b0 100644
--- a/hawkbit-device-simulator/src/main/resources/application.properties
+++ b/hawkbit-device-simulator/src/main/resources/application.properties
@@ -28,7 +28,8 @@ hawkbit.device.simulator.attributes[1].value=1.1
hawkbit.device.simulator.attributes[2].key=serial
hawkbit.device.simulator.attributes[2].value=${random.value}
-endpoints.health.enabled=true
+management.endpoints.enabled-by-default=false
+management.endpoint.health.enabled=true
## Configuration for local RabbitMQ integration
spring.rabbitmq.username=guest
@@ -38,5 +39,4 @@ spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.dynamic=true
-security.basic.enabled=false
server.port=8083
diff --git a/hawkbit-gcp-iot-core/.gitignore b/hawkbit-gcp-iot-core/.gitignore
new file mode 100644
index 0000000..cfb6698
--- /dev/null
+++ b/hawkbit-gcp-iot-core/.gitignore
@@ -0,0 +1,5 @@
+/bin/
+/target/
+/pom2.xml
+/pom3.xml
+/pom4.xml
diff --git a/hawkbit-gcp-iot-core/README.md b/hawkbit-gcp-iot-core/README.md
new file mode 100644
index 0000000..708a95f
--- /dev/null
+++ b/hawkbit-gcp-iot-core/README.md
@@ -0,0 +1,150 @@
+# hawkBit GCP Device Simulator
+
+
+## Spin a VM
+
+Use the installation script: [vmInstallDependencies.sh](./vmInstallDependencies.sh)
+
+or
+install the following:
+### git:
+`sudo apt-get install git`
+
+### java 8
+
+- `sudo apt-get install openjdk-8-jdk`
+
+- `sudo update-alternatives --config java`
+
+### docker
+
+Please read the following if you want to know more about how to install it [here](https://docs.docker.com/install/linux/docker-ce/debian/)
+
+- `sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common`
+- `curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -`
+- `sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"`
+- `sudo apt-get update`
+- `sudo apt-get install docker-ce docker-ce-cli containerd.io`
+
+### maven
+
+`sudo apt-get install maven`
+
+### create a service account
+### add the service account to the VM in the configuration
+
+## First Credentials for GCP
+- use the same service account
+- Create a json file [link](https://docs.cloudendure.com/Content/Generating_and_Using_Your_Credentials/Working_with_GCP_Credentials/Generating_the_Required_GCP_Credentials/Generating_the_Required_GCP_Credentials.htm)
+
+- Rename the downloaded file to `keys.json`
+
+- Add it to `src/main/resources`
+
+## Device Registry
+
+For now, this handler supports only one registry
+
+## GCP Config
+
+- Set the projectId and the cloud region in the GCP_OTA.java
+- Create a `state` subscription on the state topic
+- Create a bucket: gsutil mb gs:/firmware-ota/
+- enable the Token Service API: `cloud iot token`
+
+
+# hawkBit Device Simulator
+
+The device simulator handles software update commands from the update server. It is designed to be used very conveniently,
+for example, from within a browser. Hence, all the endpoints use the GET verb.
+-Dhawkbit.device.simulator.amqp.enabled=true
+
+# Open Ports
+
+- 8080/tcp —> hawkbit
+- 8083/tcp —> gcp manager
+- 3306/tcp, 33060/tcp —> Mysql
+- 4369/tcp, 5671-5672/tcp, 15671-15672/tcp, 25672/tcp —> rabbitMQ
+
+# docker on debian
+
+if you had any difficulty installing docker compose follow the following
+
+1- Open `docker-compose-stack.yml` and remove the hawkBit simulator part, since we want to run the GCP Manager on the same port
+```
+
+ image: "hawkbit/hawkbit-device-simulator:latest"
+ networks:
+ - hawknet
+ ports:
+ - "8083:8083"
+ deploy:
+ restart_policy:
+ condition: on-failure
+ environment:
+ - 'HAWKBIT_DEVICE_SIMULATOR_AUTOSTARTS_[0]_TENANT=DEFAULT'
+ - 'SPRING_RABBITMQ_VIRTUALHOST=/'
+ - 'SPRING_RABBITMQ_HOST=rabbitmq'
+ - 'SPRING_RABBITMQ_PORT=5672'
+ - 'SPRING_RABBITMQ_USERNAME=guest'
+ - 'SPRING_RABBITMQ_PASSWORD=guest'
+```
+
+2 - Run the following to start it
+```
+sudo docker swarm init
+sudo docker stack deploy -c docker-compose-stack.yml hawkbit
+```
+
+
+## Firebase config
+Follow these steps to configurate firebase with the java sdk [steps](https://firebase.google.com/docs/admin/setup)
+Generate the file and place it in `src/main/resources` and name it `firebasekeys.json`
+
+## MySQL Info
+ MYSQL_DATABASE: "hawkbit"
+ MYSQL_USER: "root"
+ port : 3306
+
+## Run on your own workstation
+```
+mvn spring-boot:run
+```
+or use the the [runSpring.sh](./runSpring.sh)
+
+## Create Software Distribution
+
+## Tag your Devices
+
+## Create a Target Filter
+
+## Configure the Rollout
+
+- Error threshold 0
+- Trigger threshold 100
+
+
+
+Follow the same config as in the
+
+
+
+
+## Notes
+
+The simulator has user authentication enabled in **cloud profile**. Default credentials:
+* username : admin
+* passwd : admin
+
+This can be configured/disabled by spring boot properties
+
+## hawkBit APIs
+
+In case there is no AMQP message broker (like rabbitMQ) running, you can disable the AMQP support for the device simulator, so the simulator is not trying to connect to an amqp message broker.
+
+Configuration property `hawkbit.device.simulator.amqp.enabled=false`
+
+## Populate GCP devices
+```
+http://localhost:8083/gcp
+```
\ No newline at end of file
diff --git a/hawkbit-gcp-iot-core/docker/0.2.0-SNAPSHOT/Dockerfile b/hawkbit-gcp-iot-core/docker/0.2.0-SNAPSHOT/Dockerfile
new file mode 100644
index 0000000..08f5a30
--- /dev/null
+++ b/hawkbit-gcp-iot-core/docker/0.2.0-SNAPSHOT/Dockerfile
@@ -0,0 +1,18 @@
+FROM openjdk:8u171-jre-alpine
+
+MAINTAINER Kai Zimmermann
+
+ENV HAWKBIT_SIM_VERSION=0.2.0-SNAPSHOT \
+ HAWKBIT_SIM_HOME=/opt/hawkbit-simulator
+
+# Http port
+EXPOSE 8083
+
+RUN set -x \
+ && mkdir -p $HAWKBIT_SIM_HOME \
+ && cd $HAWKBIT_SIM_HOME \
+ && apk add --no-cache libressl wget \
+ && wget -O hawkbit-simluator.jar --no-verbose "http://repo.eclipse.org/service/local/artifact/maven/redirect?r=hawkbit-snapshots&g=org.eclipse.hawkbit&a=hawkbit-device-simulator&v=0.2.0-SNAPSHOT"
+
+WORKDIR $HAWKBIT_SIM_HOME
+ENTRYPOINT ["java","-jar","hawkbit-simluator.jar"]
diff --git a/hawkbit-gcp-iot-core/docker/0.3.0-SNAPSHOT/Dockerfile b/hawkbit-gcp-iot-core/docker/0.3.0-SNAPSHOT/Dockerfile
new file mode 100644
index 0000000..18cc6b5
--- /dev/null
+++ b/hawkbit-gcp-iot-core/docker/0.3.0-SNAPSHOT/Dockerfile
@@ -0,0 +1,10 @@
+FROM openjdk:8-jre
+FROM jetty
+
+MAINTAINER Charbel Kaed
+
+EXPOSE 8083
+
+ADD target/hawkbit-gcp-iot-manager-0.3.0-SNAPSHOT.jar /opt/hawkbit-gcp-iot-manager-0.3.0-SNAPSHOT.jar
+
+ENTRYPOINT ["java","-jar","/opt/hawkbit-gcp-iot-manager-0.3.0-SNAPSHOT.jar"]
\ No newline at end of file
diff --git a/hawkbit-gcp-iot-core/docker/0.3.0-SNAPSHOT/Dockerfile.original b/hawkbit-gcp-iot-core/docker/0.3.0-SNAPSHOT/Dockerfile.original
new file mode 100644
index 0000000..5c4ebd3
--- /dev/null
+++ b/hawkbit-gcp-iot-core/docker/0.3.0-SNAPSHOT/Dockerfile.original
@@ -0,0 +1,18 @@
+FROM openjdk:8u171-jre-alpine
+
+MAINTAINER Kai Zimmermann
+
+ENV HAWKBIT_SIM_VERSION=0.3.0-SNAPSHOT \
+ HAWKBIT_SIM_HOME=/opt/hawkbit-simulator
+
+# Http port
+EXPOSE 8083
+
+RUN set -x \
+ && mkdir -p $HAWKBIT_SIM_HOME \
+ && cd $HAWKBIT_SIM_HOME \
+ && apk add --no-cache libressl wget \
+ && wget -O hawkbit-simluator.jar --no-verbose "http://repo.eclipse.org/service/local/artifact/maven/redirect?r=hawkbit-snapshots&g=org.eclipse.hawkbit&a=hawkbit-device-simulator&v=${HAWKBIT_SIM_VERSION}"
+
+WORKDIR $HAWKBIT_SIM_HOME
+ENTRYPOINT ["java","-jar","hawkbit-simluator.jar"]
\ No newline at end of file
diff --git a/hawkbit-gcp-iot-core/docker/Dockerfile b/hawkbit-gcp-iot-core/docker/Dockerfile
new file mode 100644
index 0000000..2fec7d4
--- /dev/null
+++ b/hawkbit-gcp-iot-core/docker/Dockerfile
@@ -0,0 +1,8 @@
+FROM openjdk:8u171-jre-alpine
+
+MAINTAINER Charbel Kaed
+
+# Http port
+EXPOSE 8083
+
+ENTRYPOINT ["java","-jar","hawkbit-gcp-manager-0.3.0-SNAPSHOT.jar"]
\ No newline at end of file
diff --git a/hawkbit-gcp-iot-core/images/rolloutConfig.png b/hawkbit-gcp-iot-core/images/rolloutConfig.png
new file mode 100644
index 0000000..e694287
Binary files /dev/null and b/hawkbit-gcp-iot-core/images/rolloutConfig.png differ
diff --git a/hawkbit-gcp-iot-core/pom.xml b/hawkbit-gcp-iot-core/pom.xml
new file mode 100644
index 0000000..fbefed8
--- /dev/null
+++ b/hawkbit-gcp-iot-core/pom.xml
@@ -0,0 +1,219 @@
+
+ 4.0.0
+
+ org.eclipse.hawkbit
+ 0.3.0-SNAPSHOT
+ hawkbit-examples-parent
+
+
+ hawkbit-gcp-iot-integration
+ hawkbit-gcp-iot-manager
+ hawkBit :: GCP :: Manager
+ Device Management Federation API with GCP
+
+
+
+ charbull
+ charbelk@google.com
+ Google LLC
+ https://www.google.com
+
+ Lead
+ Committer
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ ${baseDir}
+ org.eclipse.hawkbit.handler.GcpModuleIntegrator
+ JAR
+
+
+
+
+
+
+
+ src/main/resources
+
+
+ cf
+ true
+ ${project.build.directory}
+
+ keys.jsons
+
+
+
+
+
+
+
+ org.eclipse.hawkbit
+ hawkbit-dmf-api
+
+
+ org.eclipse.hawkbit
+ hawkbit-example-ddi-feign-client
+ ${project.version}
+
+
+ org.springframework.amqp
+ spring-rabbit
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-jetty
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+ org.springframework.security
+ spring-security-web
+
+
+ org.springframework.security
+ spring-security-config
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+
+ org.springframework.cloud
+ spring-cloud-commons
+
+
+ org.springframework.cloud
+ spring-cloud-context
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ 1.2.0
+
+
+ org.json
+ json
+ 20090211
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.7.0
+
+
+ joda-time
+ joda-time
+ 2.1
+
+
+ com.google.apis
+ google-api-services-cloudiot
+ v1-rev20181120-1.27.0
+
+
+ com.google.oauth-client
+ google-oauth-client
+ 1.23.0
+
+
+ com.google.api-client
+ google-api-client
+ 1.28.0
+
+
+ com.google.auth
+ google-auth-library-appengine
+ 0.12.0
+
+
+
+ com.google.apis
+ google-api-services-iam
+ v1-rev267-1.25.0
+
+
+ commons-cli
+ commons-cli
+ 1.4
+
+
+ com.google.cloud
+ google-cloud-pubsub
+ 1.63.0
+
+
+
+ com.google.apis
+ google-api-services-storage
+ v1-rev149-1.25.0
+
+
+ com.google.cloud
+ google-cloud-firestore
+ 0.81.0-beta
+
+
+ com.google.firebase
+ firebase-admin
+ 6.7.0
+
+
+
+ com.google.guava
+ guava
+ 23.6-jre
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ com.google.truth
+ truth
+ 0.34
+ test
+
+
+
\ No newline at end of file
diff --git a/hawkbit-gcp-iot-core/runSpring.sh b/hawkbit-gcp-iot-core/runSpring.sh
new file mode 100755
index 0000000..58540b1
--- /dev/null
+++ b/hawkbit-gcp-iot-core/runSpring.sh
@@ -0,0 +1,2 @@
+mvn clean install
+mvn spring-boot:run
diff --git a/hawkbit-gcp-iot-core/src/main/java/org/eclipse/hawkbit/google/gcp/GcpBucketHandler.java b/hawkbit-gcp-iot-core/src/main/java/org/eclipse/hawkbit/google/gcp/GcpBucketHandler.java
new file mode 100644
index 0000000..1a86216
--- /dev/null
+++ b/hawkbit-gcp-iot-core/src/main/java/org/eclipse/hawkbit/google/gcp/GcpBucketHandler.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright 2019 Google LLC
+ *
+ * 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.google.gcp;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
+import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.http.InputStreamContent;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.iam.v1.IamScopes;
+import com.google.api.services.storage.Storage;
+import com.google.api.services.storage.model.Bucket;
+import com.google.api.services.storage.model.Buckets;
+import com.google.api.services.storage.model.Objects;
+import com.google.api.services.storage.model.StorageObject;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+
+
+
+public class GcpBucketHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GcpBucketHandler.class);
+
+ private static Storage storage = null;
+ static Gson gson = new Gson();
+
+ private static HttpTransport httpTransport;
+ private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
+
+
+
+ private static Storage getStorage() {
+ try {
+ if(storage == null)
+ {
+ GoogleCredential credential = GcpCredentials.getCredential()
+ .createScoped(Collections.singleton(IamScopes.CLOUD_PLATFORM));
+
+ httpTransport = GoogleNetHttpTransport.newTrustedTransport();
+ storage = new Storage.Builder(
+ httpTransport,
+ JSON_FACTORY,
+ credential
+ ).build();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return storage;
+ }
+
+ public static void uploadFirmwareToBucket(String fileUrl, String artifactName, String targetToken) throws FileNotFoundException, IOException, GeneralSecurityException {
+
+ Storage gcs = getStorage();
+ String data = HawkBitSoftwareModuleHandler.downloadFileData(fileUrl, targetToken);
+ if(!checkIfExists(artifactName))
+ {
+ LOGGER.info("Uploading to GCS artifact: "+artifactName);
+ uploadSimple(gcs, GcpOTA.BUCKET_NAME, artifactName, data);
+ }
+ }
+
+ public static String getFirmwareInfoBucket(String artifactName)
+ {
+ StorageObject storageObject = GcpBucketHandler.getStorageObjectInfo(artifactName);
+ if(storageObject != null)
+ {
+ JsonObject jsonObject = new JsonObject();
+ LOGGER.info(artifactName+" exists!");
+ jsonObject.addProperty("ObjectName", storageObject.getName());
+ jsonObject.addProperty("Url", storageObject.getMediaLink());
+ jsonObject.addProperty("Md5Hash", storageObject.getMd5Hash());
+
+ JsonObject jsonConfig = new JsonObject();
+ jsonConfig.add("firmware-update", jsonObject);
+ return gson.toJson(jsonConfig);
+ }
+ return null;
+ }
+
+
+ public static Map> getFirmwareInfoBucket_Map(String artifactName)
+ {
+ StorageObject storageObject = GcpBucketHandler.getStorageObjectInfo(artifactName);
+ if(storageObject != null)
+ {
+ Map> fw_update = new HashMap<>(1);
+ Map mapContent = new HashMap<>(3);
+ LOGGER.info(artifactName+" exists!");
+ mapContent.put(GcpOTA.OBJECT_NAME, storageObject.getName());
+ mapContent.put(GcpOTA.URL, storageObject.getMediaLink());
+ mapContent.put(GcpOTA.MD5HASH, storageObject.getMd5Hash());
+ fw_update.put(GcpOTA.FW_UPDATE, mapContent);
+ return fw_update;
+ }
+ return null;
+ }
+
+
+ public static Map>> getFirmwareInfoBucket_MapList(List modules)
+ {
+ Map>> fw_update_Map =
+ new HashMap>>(1);
+
+
+ List fwNameList = modules.stream().flatMap(mod -> mod.getArtifacts().stream())
+ .map(art -> art.getFilename())
+ .collect(Collectors.toList());
+
+ List
-
+
\ No newline at end of file