From dbc70ae374d7c78ceef93c5aa958f2d4ed8dccd7 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 3 May 2016 09:25:07 +0200 Subject: [PATCH 01/12] Added targetToken to DMF update message. Signed-off-by: Kai Zimmermann --- examples/hawkbit-mgmt-api-client/pom.xml | 2 +- .../amqp/AmqpMessageDispatcherService.java | 1 + .../amqp/AmqpMessageHandlerService.java | 3 ++- .../AmqpMessageDispatcherServiceTest.java | 20 +++++++++++-------- .../amqp/AmqpMessageHandlerServiceTest.java | 9 +++++---- .../json/model/DownloadAndUpdateRequest.java | 15 +++++++++++--- .../TargetAssignDistributionSetEvent.java | 12 ++++++++--- .../repository/DeploymentManagement.java | 9 +++++---- 8 files changed, 47 insertions(+), 24 deletions(-) diff --git a/examples/hawkbit-mgmt-api-client/pom.xml b/examples/hawkbit-mgmt-api-client/pom.xml index 9aaf53dc6..77e35df83 100644 --- a/examples/hawkbit-mgmt-api-client/pom.xml +++ b/examples/hawkbit-mgmt-api-client/pom.xml @@ -18,7 +18,7 @@ jar hawkbit-mgmt-api-client - hawkBit Management API example client + hawkBit :: Management API example client diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java index 19e0cbadf..02c72228c 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java @@ -82,6 +82,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { .getSoftwareModules(); final DownloadAndUpdateRequest downloadAndUpdateRequest = new DownloadAndUpdateRequest(); downloadAndUpdateRequest.setActionId(targetAssignDistributionSetEvent.getActionId()); + downloadAndUpdateRequest.setTargetToken(targetAssignDistributionSetEvent.getTargetToken()); for (final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule : modules) { final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(controllerId, softwareModule); diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java index 447a8ffca..da7c10800 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java @@ -305,7 +305,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService { final List softwareModuleList = controllerManagement .findSoftwareModulesByDistributionSet(distributionSet); eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), - target.getControllerId(), action.getId(), softwareModuleList, target.getTargetInfo().getAddress())); + target.getControllerId(), action.getId(), softwareModuleList, target.getTargetInfo().getAddress(), + target.getSecurityToken())); } diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java index f2c3d254c..ec6ed05b0 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java @@ -58,6 +58,12 @@ import ru.yandex.qatools.allure.annotations.Stories; @Stories("AmqpMessage Dispatcher Service Test") public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWithMongoDB { + private static final String TENANT = "default"; + + private static final URI AMQP_URI = IpUtil.createAmqpUri("vHost", "mytest"); + + private static final String TEST_TOKEN = "testToken"; + private AmqpMessageDispatcherService amqpMessageDispatcherService; private RabbitTemplate rabbitTemplate; @@ -89,8 +95,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit @Description("Verfies that download and install event with no software modul works") public void testSendDownloadRequesWithEmptySoftwareModules() { final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( - 1L, "default", CONTROLLER_ID, 1l, new ArrayList(), - IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, new ArrayList(), AMQP_URI, TEST_TOKEN); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); @@ -104,7 +109,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, distributionSetManagement); final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( - 1L, "default", CONTROLLER_ID, 1l, dsA.getModules(), IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); @@ -143,7 +148,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList); final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( - 1L, "default", CONTROLLER_ID, 1l, dsA.getModules(), IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); @@ -162,7 +167,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit @Description("Verfies that send cancel event works") public void testSendCancelRequest() { final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent( - 1L, "default", CONTROLLER_ID, 1l, IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, AMQP_URI); amqpMessageDispatcherService .targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent); final Message sendMessage = createArgumentCapture(cancelTargetAssignmentDistributionSetEvent.getTargetAdress()); @@ -187,13 +192,12 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit downloadAndUpdateRequest.getActionId(), Long.valueOf(1)); assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL, sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC)); + assertEquals("Security token of target", downloadAndUpdateRequest.getTargetToken(), TEST_TOKEN); + return downloadAndUpdateRequest; } - /** - * @param sendMessage - */ private void assertEventMessage(final Message sendMessage) { assertNotNull("The message should not be null", sendMessage); diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java index 19a7be3bc..18ee0bde4 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java @@ -339,14 +339,14 @@ public class AmqpMessageHandlerServiceTest { @Test @Description("Tests TODO") - public void lookupNextUpdateActionAfterFinished() throws IllegalArgumentException, IllegalAccessException { + public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException { // Mock final Action action = createActionWithTarget(22L, Status.FINISHED); when(controllerManagementMock.findActionWithDetails(Matchers.any())).thenReturn(action); when(controllerManagementMock.addUpdateActionStatus(Matchers.any(), Matchers.any())).thenReturn(action); // for the test the same action can be used - final List actionList = new ArrayList(); + final List actionList = new ArrayList<>(); actionList.add(action); when(controllerManagementMock.findActionByTargetAndActive(Matchers.any())).thenReturn(actionList); @@ -372,6 +372,8 @@ public class AmqpMessageHandlerServiceTest { assertThat(targetAssignDistributionSetEvent.getControllerId()).as("event has wrong controller id") .isEqualTo("target1"); + assertThat(targetAssignDistributionSetEvent.getTargetToken()).as("targetoken not filled correctly") + .isEqualTo(action.getTarget().getSecurityToken()); assertThat(targetAssignDistributionSetEvent.getActionId()).as("event has wrong action id").isEqualTo(22L); assertThat(targetAssignDistributionSetEvent.getSoftwareModules()).as("event has wrong sofware modules") .isEqualTo(softwareModuleList); @@ -411,8 +413,7 @@ public class AmqpMessageHandlerServiceTest { return softwareModuleList; } - private Action createActionWithTarget(final Long targetId, final Status status) - throws IllegalArgumentException, IllegalAccessException { + private Action createActionWithTarget(final Long targetId, final Status status) throws IllegalAccessException { // is needed for the creation of targets initalizeSecurityTokenGenerator(); diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java index 4344c5416..f34bab6dd 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java @@ -19,15 +19,16 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * JSON representation of download and update request. * - * - * - * */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class DownloadAndUpdateRequest { @JsonProperty private Long actionId; + + @JsonProperty + private String targetToken; + @JsonProperty private final List softwareModules = new LinkedList<>(); @@ -39,6 +40,14 @@ public class DownloadAndUpdateRequest { this.actionId = correlator; } + public String getTargetToken() { + return targetToken; + } + + public void setTargetToken(final String targetToken) { + this.targetToken = targetToken; + } + public List getSoftwareModules() { return softwareModules; } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java index b286ac6ea..68b3f1289 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java @@ -16,8 +16,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; /** * Event that gets sent when a distribution set gets assigned to a target. * - * - * */ public class TargetAssignDistributionSetEvent extends AbstractEvent { @@ -25,6 +23,7 @@ public class TargetAssignDistributionSetEvent extends AbstractEvent { private final String controllerId; private final Long actionId; private final URI targetAdress; + private final String targetToken; /** * Creates a new {@link TargetAssignDistributionSetEvent}. @@ -41,14 +40,18 @@ public class TargetAssignDistributionSetEvent extends AbstractEvent { * the software modules which have been assigned to the target * @param targetAdress * the targetAdress of the target + * @param targetToken + * the authentication token of the target */ public TargetAssignDistributionSetEvent(final long revision, final String tenant, final String controllerId, - final Long actionId, final Collection softwareModules, final URI targetAdress) { + final Long actionId, final Collection softwareModules, final URI targetAdress, + final String targetToken) { super(revision, tenant); this.controllerId = controllerId; this.actionId = actionId; this.softwareModules = softwareModules; this.targetAdress = targetAdress; + this.targetToken = targetToken; } /** @@ -77,4 +80,7 @@ public class TargetAssignDistributionSetEvent extends AbstractEvent { return targetAdress; } + public String getTargetToken() { + return targetToken; + } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java index 77f71bebf..e64eeab13 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java @@ -389,8 +389,8 @@ public class DeploymentManagement { softwareModules)); } - private Action createTargetAction(final Map targetsWithActionMap, final Target target, - final DistributionSet set, final Rollout rollout, final RolloutGroup rolloutGroup) { + private static Action createTargetAction(final Map targetsWithActionMap, + final Target target, final DistributionSet set, final Rollout rollout, final RolloutGroup rolloutGroup) { final Action actionForTarget = new Action(); final TargetWithActionType targetWithActionType = targetsWithActionMap.get(target.getControllerId()); actionForTarget.setActionType(targetWithActionType.getActionType()); @@ -421,13 +421,14 @@ public class DeploymentManagement { afterCommit.afterCommit(() -> { eventBus.post(new TargetInfoUpdateEvent(target.getTargetInfo())); eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), - target.getControllerId(), actionId, softwareModules, target.getTargetInfo().getAddress())); + target.getControllerId(), actionId, softwareModules, target.getTargetInfo().getAddress(), + target.getSecurityToken())); }); } /** * Removes {@link UpdateAction}s that are no longer necessary and sends - * cancelations to the controller. + * cancellations to the controller. * * @param myTarget * to override {@link UpdateAction}s From 85263e475db3b40f0f63b48e25958f1b9ebaba0d Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 3 May 2016 09:48:55 +0200 Subject: [PATCH 02/12] use correct term for token. Similar to mgmt API. Signed-off-by: Kai Zimmermann --- .../hawkbit/amqp/AmqpMessageDispatcherService.java | 2 +- .../hawkbit/amqp/AmqpMessageDispatcherServiceTest.java | 2 +- .../dmf/json/model/DownloadAndUpdateRequest.java | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java index 02c72228c..32bcb02a5 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java @@ -82,7 +82,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { .getSoftwareModules(); final DownloadAndUpdateRequest downloadAndUpdateRequest = new DownloadAndUpdateRequest(); downloadAndUpdateRequest.setActionId(targetAssignDistributionSetEvent.getActionId()); - downloadAndUpdateRequest.setTargetToken(targetAssignDistributionSetEvent.getTargetToken()); + downloadAndUpdateRequest.setTargetSecurityToken(targetAssignDistributionSetEvent.getTargetToken()); for (final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule : modules) { final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(controllerId, softwareModule); diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java index ec6ed05b0..4e0852ff3 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java @@ -192,7 +192,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit downloadAndUpdateRequest.getActionId(), Long.valueOf(1)); assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL, sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC)); - assertEquals("Security token of target", downloadAndUpdateRequest.getTargetToken(), TEST_TOKEN); + assertEquals("Security token of target", downloadAndUpdateRequest.getTargetSecurityToken(), TEST_TOKEN); return downloadAndUpdateRequest; diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java index f34bab6dd..88cb80975 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java @@ -27,7 +27,7 @@ public class DownloadAndUpdateRequest { private Long actionId; @JsonProperty - private String targetToken; + private String targetSecurityToken; @JsonProperty private final List softwareModules = new LinkedList<>(); @@ -40,12 +40,12 @@ public class DownloadAndUpdateRequest { this.actionId = correlator; } - public String getTargetToken() { - return targetToken; + public String getTargetSecurityToken() { + return targetSecurityToken; } - public void setTargetToken(final String targetToken) { - this.targetToken = targetToken; + public void setTargetSecurityToken(final String targetSecurityToken) { + this.targetSecurityToken = targetSecurityToken; } public List getSoftwareModules() { From 2177271a49e6cdcee6f692e9048bb26e430f9e79 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 3 May 2016 15:44:03 +0200 Subject: [PATCH 03/12] Added save (auto) close. Signed-off-by: Kai Zimmermann --- .../eclipse/hawkbit/artifact/repository/ArtifactStore.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java index 6981834b4..94b093cb3 100644 --- a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java +++ b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java @@ -200,9 +200,9 @@ public class ArtifactStore implements ArtifactRepository { String sha1Hash; // compute digest final MessageDigest md = MessageDigest.getInstance("SHA-1"); - final DigestOutputStream dos = new DigestOutputStream(os, md); - ByteStreams.copy(stream, dos); - dos.close(); + try (final DigestOutputStream dos = new DigestOutputStream(os, md)) { + ByteStreams.copy(stream, dos); + } sha1Hash = BaseEncoding.base16().lowerCase().encode(md.digest()); if (providedSHA1Sum != null && !providedSHA1Sum.equalsIgnoreCase(sha1Hash)) { throw new HashNotMatchException( From 7c4351faa55b18e919b256dba4368e82a6adaad6 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 3 May 2016 15:44:46 +0200 Subject: [PATCH 04/12] Fixed wrong handling of multi line message status. Signed-off-by: Kai Zimmermann --- .../org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java index da7c10800..f26d7f3f7 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java @@ -337,9 +337,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService { final Action action = checkActionExist(message, actionUpdateStatus); final ActionStatus actionStatus = new ActionStatus(); - final List messageText = actionUpdateStatus.getMessage(); - final String messageString = String.join(", ", messageText); - actionStatus.addMessage(messageString); + actionUpdateStatus.getMessage().forEach(actionStatus::addMessage); + actionStatus.setAction(action); actionStatus.setOccurredAt(System.currentTimeMillis()); From f32f612e839ad6fa3feccf604e673e8b627f6c32 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 3 May 2016 15:56:16 +0200 Subject: [PATCH 05/12] Improved readability of action status messages that are created by the update server itself. Signed-off-by: Kai Zimmermann --- .../repository/ControllerManagement.java | 9 ++++++--- .../controller/ArtifactStoreController.java | 6 ++++-- .../hawkbit/controller/RootController.java | 17 ++++++++++------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java index dc097a7e3..58ae2ad97 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -63,6 +63,8 @@ public class ControllerManagement { private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class); private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos"); + public static final String SERVER_MESSAGE_PREFIX = "Update Server: "; + @Autowired private EntityManager entityManager; @@ -341,13 +343,14 @@ public class ControllerManagement { break; case CANCELED: case FINISHED: - // in case of successful cancelation we also report the success at + // in case of successful cancellation we also report the success at // the canceled action itself. - actionStatus.addMessage("Cancelation completion is finished sucessfully."); + actionStatus.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Cancellation completion is finished sucessfully."); deploymentManagement.successCancellation(action); break; case RETRIEVED: - actionStatus.addMessage("Cancelation request retrieved"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Cancellation request retrieved."); break; default: } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java index c2dbd3ba5..a36443024 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java @@ -143,9 +143,11 @@ public class ArtifactStoreController { actionStatus.setStatus(Status.DOWNLOAD); if (range != null) { - actionStatus.addMessage("It is a partial download request: " + range); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + + " of: " + request.getRequestURI()); } else { - actionStatus.addMessage("Target downloads"); + actionStatus.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI()); } controllerManagement.addActionStatusMessage(actionStatus); return action; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java index f704acd5e..000e1e2e5 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java @@ -216,9 +216,11 @@ public class RootController { statusMessage.setStatus(Status.DOWNLOAD); if (range != null) { - statusMessage.addMessage("It is a partial download request: " + range); + statusMessage.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + + " of: " + request.getRequestURI()); } else { - statusMessage.addMessage("Controller downloads"); + statusMessage.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI()); } controllerManagement.addActionStatusMessage(statusMessage); return action; @@ -388,13 +390,13 @@ public class RootController { LOG.debug("Controller confirmed cancel (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.CANCELED); - actionStatus.addMessage("Controller confirmed cancelation"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target confirmed cancelation"); break; case REJECTED: LOG.info("Controller reported internal error (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.WARNING); - actionStatus.addMessage("Controller reported internal ERROR and REJECTED update."); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target REJECTED update."); break; case CLOSED: handleClosedUpdateStatus(feedback, targetid, actionid, actionStatus); @@ -421,7 +423,8 @@ public class RootController { LOG.debug("Controller reported intermediate status (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.RUNNING); - actionStatus.addMessage("Controller reported: " + feedback.getStatus().getExecution()); + actionStatus.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported: " + feedback.getStatus().getExecution()); } private static void handleClosedUpdateStatus(final ActionFeedback feedback, final String targetid, @@ -430,10 +433,10 @@ public class RootController { feedback.getStatus().getExecution()); if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) { actionStatus.setStatus(Status.ERROR); - actionStatus.addMessage("Controller reported CLOSED with ERROR!"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with ERROR!"); } else { actionStatus.setStatus(Status.FINISHED); - actionStatus.addMessage("Controller reported CLOSED with OK!"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with OK!"); } } From 7e941cf64d9ba2c2204b751c01b62c7d431ad2f2 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 3 May 2016 16:16:36 +0200 Subject: [PATCH 06/12] Teached simulator to download artifacts including SHA1 hash check and targetToken usage. Signed-off-by: Kai Zimmermann --- examples/hawkbit-device-simulator/pom.xml | 13 +- .../simulator/AbstractSimulatedDevice.java | 42 ++--- .../hawkbit/simulator/DDISimulatedDevice.java | 50 +++--- .../hawkbit/simulator/DMFSimulatedDevice.java | 5 +- .../simulator/DeviceSimulatorUpdater.java | 152 ++++++++++++++++-- .../simulator/NextPollTimeController.java | 18 +-- .../simulator/SimulatedDeviceFactory.java | 13 +- .../hawkbit/simulator/UpdateStatus.java | 58 +++++++ .../simulator/amqp/SpReceiverService.java | 15 +- .../simulator/amqp/SpSenderService.java | 53 +++--- .../simulator/event/ProgressUpdate.java | 2 - .../hawkbit/simulator/ui/SimulatorView.java | 98 +++++------ 12 files changed, 333 insertions(+), 186 deletions(-) create mode 100644 examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java diff --git a/examples/hawkbit-device-simulator/pom.xml b/examples/hawkbit-device-simulator/pom.xml index c74eace3e..33d165584 100644 --- a/examples/hawkbit-device-simulator/pom.xml +++ b/examples/hawkbit-device-simulator/pom.xml @@ -1,4 +1,3 @@ - - 4.0.0 @@ -133,6 +133,15 @@ spring-boot-configuration-processor true + + org.scala-lang + scala-library + 2.10.4 + + + org.apache.httpcomponents + httpclient + 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 index 474acb6c4..890f43367 100644 --- 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 @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.simulator; +import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus; + /** * The bean of a simulated device which can be stored in the * {@link DeviceSimulatorRepository} or shown in the UI. @@ -22,16 +24,15 @@ public abstract class AbstractSimulatedDevice { private Status status; private double progress; private String swversion = "unknown"; - private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL; + private UpdateStatus updateStatus = new UpdateStatus(ResponseStatus.SUCCESSFUL, "Simulation complete!"); private Protocol protocol = Protocol.DMF_AMQP; + private String targetSecurityToken; private int nextPollCounterSec; /** * Enum definition of the protocol to be used for the simulated device. * - * @author Michael Hirsch - * */ public enum Protocol { /** @@ -69,24 +70,6 @@ public abstract class AbstractSimulatedDevice { 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. */ @@ -158,12 +141,12 @@ public abstract class AbstractSimulatedDevice { this.swversion = swversion; } - public ResponseStatus getResponseStatus() { - return responseStatus; + public UpdateStatus getUpdateStatus() { + return updateStatus; } - public void setResponseStatus(final ResponseStatus responseStatus) { - this.responseStatus = responseStatus; + public void setUpdateStatus(final UpdateStatus updateStatus) { + this.updateStatus = updateStatus; } public Protocol getProtocol() { @@ -177,4 +160,13 @@ public abstract class AbstractSimulatedDevice { public void setNextPollCounterSec(final int nextPollDelayInSec) { this.nextPollCounterSec = nextPollDelayInSec; } + + public String getTargetSecurityToken() { + return targetSecurityToken; + } + + public void setTargetSecurityToken(final String targetSecurityToken) { + this.targetSecurityToken = targetSecurityToken; + } + } 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 index b58d3a413..26e613dd9 100644 --- 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 @@ -8,8 +8,6 @@ */ package org.eclipse.hawkbit.simulator; -import java.util.concurrent.ScheduledExecutorService; - import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,7 +16,7 @@ import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.PathNotFoundException; /** - * @author Michael Hirsch + * A simulated device using the DDI API of the hawkBit update server. * */ public class DDISimulatedDevice extends AbstractSimulatedDevice { @@ -26,12 +24,12 @@ 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 final DeviceSimulatorUpdater deviceUpdater; + private volatile boolean removed; private volatile Long currentActionId; - private final DeviceSimulatorUpdater deviceUpdater; /** * @param id @@ -42,18 +40,14 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { * 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) { + final ControllerResource controllerResource, final DeviceSimulatorUpdater deviceUpdater) { super(id, tenant, Protocol.DDI_HTTP); this.pollDelaySec = pollDelaySec; this.controllerResource = controllerResource; - this.pollthreadpool = pollthreadpool; this.deviceUpdater = deviceUpdater; setNextPollCounterSec(pollDelaySec); } @@ -76,27 +70,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { 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("?"))); + 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, (device, actionId1) -> { - switch (device.getResponseStatus()) { - case SUCCESSFUL: - controllerResource.postSuccessFeedback(getTenant(), getId(), - actionId1); - break; - case ERROR: - controllerResource.postErrorFeedback(getTenant(), getId(), - actionId1); - break; - default: - throw new IllegalStateException( - "simulated device has an unknown response status + " + device.getResponseStatus()); - } - currentActionId = null; - }); + startDdiUpdate(actionId, swVersion); } } catch (final PathNotFoundException e) { // href might not be in the json response, so ignore @@ -106,4 +85,21 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { } } + + private void startDdiUpdate(final long actionId, final String swVersion) { + deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, null, null, (device, actionId1) -> { + switch (device.getUpdateStatus().getResponseStatus()) { + case SUCCESSFUL: + controllerResource.postSuccessFeedback(getTenant(), getId(), actionId1); + break; + case ERROR: + controllerResource.postErrorFeedback(getTenant(), getId(), actionId1); + break; + default: + throw new IllegalStateException("simulated device has an unknown response status + " + + device.getUpdateStatus().getResponseStatus()); + } + currentActionId = null; + }); + } } 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 index b9fdc827c..6b79a85b8 100644 --- 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 @@ -9,10 +9,7 @@ package org.eclipse.hawkbit.simulator; /** - * An simulated device using the DMF API of the hawkbit update server. - * - * @author Michael Hirsch - * + * A simulated device using the DMF API of the hawkBit update server. */ public class DMFSimulatedDevice extends AbstractSimulatedDevice { 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 index afc3a2569..12ff7dbd2 100644 --- 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 @@ -8,27 +8,52 @@ */ package org.eclipse.hawkbit.simulator; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.DigestOutputStream; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLContextBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.eclipse.hawkbit.dmf.json.model.Artifact; +import org.eclipse.hawkbit.dmf.json.model.SoftwareModule; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; +import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus; import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.event.InitUpdate; import org.eclipse.hawkbit.simulator.event.ProgressUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.google.common.eventbus.EventBus; +import com.google.common.io.BaseEncoding; +import com.google.common.io.ByteStreams; /** - * @author Michael Hirsch + * Update simulation handler. * */ @Service public class DeviceSimulatorUpdater { + private static final Logger LOGGER = LoggerFactory.getLogger(DeviceSimulatorUpdater.class); private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4); @@ -54,14 +79,18 @@ public class DeviceSimulatorUpdater { * @param actionId * the actionId from the hawkbit update server to start the * update. - * @param swVersion + * @param modules * the software module version from the hawkbit update server + * @param swVersion + * the software version as static value in case modules is null + * @param targetSecurityToken + * the target security token for download authentication * @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 List modules, final String targetSecurityToken, final UpdaterCallback callback) { AbstractSimulatedDevice device = repository.get(tenant, id); // plug and play - non existing device will be auto created @@ -70,11 +99,18 @@ public class DeviceSimulatorUpdater { } device.setProgress(0.0); - device.setSwversion(swVersion); + + if (modules == null) { + device.setSwversion(swVersion); + } else { + device.setSwversion(modules.stream().map(sm -> sm.getModuleVersion()).collect(Collectors.joining(", "))); + } + device.setTargetSecurityToken(targetSecurityToken); eventbus.post(new InitUpdate(device)); - threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), - 2_000, TimeUnit.MILLISECONDS); + threadPool.schedule( + new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules), 2_000, + TimeUnit.MILLISECONDS); } private static final class DeviceSimulatorUpdateThread implements Runnable { @@ -85,38 +121,130 @@ public class DeviceSimulatorUpdater { private final long actionId; private final EventBus eventbus; private final UpdaterCallback callback; + private final List modules; private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService, - final long actionId, final EventBus eventbus, final UpdaterCallback callback) { + final long actionId, final EventBus eventbus, final UpdaterCallback callback, + final List modules) { this.device = device; this.spSenderService = spSenderService; this.actionId = actionId; this.eventbus = eventbus; this.callback = callback; + this.modules = modules; } @Override public void run() { + if (device.getProgress() <= 0 && modules != null) { + device.setUpdateStatus(simulateDownloads(device.getTargetSecurityToken())); + if (device.getUpdateStatus().getResponseStatus().equals(ResponseStatus.ERROR)) { + callback.updateFinished(device, actionId); + eventbus.post(new ProgressUpdate(device)); + return; + } + } + final double newProgress = device.getProgress() + 0.2; device.setProgress(newProgress); if (newProgress < 1.0) { threadPool.schedule( - new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), + new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules), rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS); } else { callback.updateFinished(device, actionId); } eventbus.post(new ProgressUpdate(device)); } + + private UpdateStatus simulateDownloads(final String targetToken) { + final List status = new ArrayList<>(); + + LOGGER.info("Simulate downloads for {}", device.getId()); + + modules.forEach(module -> module.getArtifacts() + .forEach(artifact -> handleArtifacts(targetToken, status, artifact))); + + final UpdateStatus result = new UpdateStatus(ResponseStatus.SUCCESSFUL); + result.getStatusMessages().add("Simulation complete!"); + status.forEach(download -> { + result.getStatusMessages().addAll(download.getStatusMessages()); + if (download.getResponseStatus().equals(ResponseStatus.ERROR)) { + result.setResponseStatus(ResponseStatus.ERROR); + } + }); + + LOGGER.info("Download simulations complete for {}", device.getId()); + + return result; + } + + private static void handleArtifacts(final String targetToken, final List status, + final Artifact artifact) { + artifact.getUrls().entrySet().forEach(entry -> { + switch (entry.getKey()) { + case HTTPS: + status.add(downloadUrl(entry.getValue(), targetToken, artifact.getHashes().getSha1())); + break; + default: + // not supported yet + break; + } + }); + } + + private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash) { + LOGGER.debug("Downloading " + url); + + long overallread = 0; + try { + final CloseableHttpClient httpclient = createHttpClientThatAcceptsAllServerCerts(); + final HttpGet request = new HttpGet(url); + request.addHeader("TargetToken", targetToken); + + final String sha1HashResult; + try (final CloseableHttpResponse response = httpclient.execute(request)) { + final File tempFile = File.createTempFile("uploadFile", null); + final MessageDigest md = MessageDigest.getInstance("SHA-1"); + + try (final DigestOutputStream dos = new DigestOutputStream(new FileOutputStream(tempFile), md)) { + overallread = ByteStreams.copy(response.getEntity().getContent(), dos); + sha1HashResult = BaseEncoding.base16().lowerCase().encode(md.digest()); + } finally { + tempFile.delete(); + } + } + + if (!sha1Hash.equals(sha1HashResult)) { + final String message = "Download " + url + " failed with SHA1 hash missmatch (Expected: " + sha1Hash + + " but got: " + sha1HashResult + ")"; + LOGGER.debug(message); + return new UpdateStatus(ResponseStatus.ERROR, message); + } + + } catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + LOGGER.error("Failed to download {}", url, e); + return new UpdateStatus(ResponseStatus.ERROR, "Failed to download " + url + ": " + e.getMessage()); + } + + final String message = "Downloaded " + url + " (" + overallread + " bytes)"; + LOGGER.debug(message); + return new UpdateStatus(ResponseStatus.SUCCESSFUL, message); + } + + private static CloseableHttpClient createHttpClientThatAcceptsAllServerCerts() + throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + final SSLContextBuilder builder = new SSLContextBuilder(); + builder.loadTrustMaterial(null, (chain, authType) -> true); + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build()); + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } } /** * 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 - * + * send the result to the hawkBit update server back. * */ @FunctionalInterface public interface UpdaterCallback { 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 index 9c78ec65a..956d6d36a 100644 --- 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 @@ -26,9 +26,6 @@ import com.google.common.eventbus.EventBus; /** * Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every * second. - * - * @author Michael Hirsch - * */ @Component public class NextPollTimeController { @@ -59,16 +56,15 @@ public class NextPollTimeController { devices.forEach(device -> { int nextCounter = device.getNextPollCounterSec() - 1; - if (nextCounter < 0) { - if (device instanceof DDISimulatedDevice) { - try { - pollService.submit(() -> ((DDISimulatedDevice) device).poll()); - } catch (final IllegalStateException e) { - LOGGER.trace("Device could not be polled", e); - } - nextCounter = ((DDISimulatedDevice) device).getPollDelaySec(); + if (nextCounter < 0 && device instanceof DDISimulatedDevice) { + try { + pollService.submit(() -> ((DDISimulatedDevice) device).poll()); + } catch (final IllegalStateException e) { + LOGGER.trace("Device could not be polled", 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 index d3e080806..f29aad001 100644 --- 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 @@ -9,8 +9,6 @@ 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; @@ -24,15 +22,9 @@ 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; @@ -47,7 +39,8 @@ public class SimulatedDeviceFactory { * the protocol of the device * @return the created simulated device */ - public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol) { + public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, + final Protocol protocol) { return createSimulatedDevice(id, tenant, protocol, 30, null, null); } @@ -80,7 +73,7 @@ public class SimulatedDeviceFactory { 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); + return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, deviceUpdater); default: throw new IllegalArgumentException("Protocol " + protocol + " unknown"); } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java new file mode 100644 index 000000000..49e9947d7 --- /dev/null +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java @@ -0,0 +1,58 @@ +/** + * 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.ArrayList; +import java.util.List; + +/** + * Update status of the simulated update. + * + */ +public class UpdateStatus { + private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL; + private final List statusMessages = new ArrayList<>(); + + public UpdateStatus(final ResponseStatus responseStatus) { + this.responseStatus = responseStatus; + } + + public UpdateStatus(final ResponseStatus responseStatus, final String message) { + this(responseStatus); + statusMessages.add(message); + } + + public ResponseStatus getResponseStatus() { + return responseStatus; + } + + public void setResponseStatus(final ResponseStatus responseStatus) { + this.responseStatus = responseStatus; + } + + public List getStatusMessages() { + return statusMessages; + } + + /** + * The status to response to the hawkBit update server if an simulated + * update process should be respond with successful or failure update. + */ + public enum ResponseStatus { + /** + * updated has been successful and response the successful update. + */ + SUCCESSFUL, + /** + * updated has been not successful and response the error update. + */ + ERROR; + } + +} \ No newline at end of file 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 f22839422..12e540fc9 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 @@ -25,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; +import com.google.common.collect.Lists; + /** * Handle all incoming Messages from hawkBit update server. * @@ -109,7 +111,7 @@ public class SpReceiverService extends ReceiverService { final Long actionId = convertMessage(message, Long.class); final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId); - spSenderService.finishUpdateProcess(update, "Simulation canceled"); + spSenderService.finishUpdateProcess(update, Lists.newArrayList("Simulation canceled")); } private void handleUpdateProcess(final Message message, final String thingId) { @@ -120,19 +122,20 @@ public class SpReceiverService extends ReceiverService { final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message, DownloadAndUpdateRequest.class); final Long actionId = downloadAndUpdateRequest.getActionId(); + final String targetSecurityToken = downloadAndUpdateRequest.getTargetSecurityToken(); - deviceUpdater.startUpdate(tenant, thingId, actionId, - downloadAndUpdateRequest.getSoftwareModules().get(0).getModuleVersion(), (device, actionId1) -> { - switch (device.getResponseStatus()) { + deviceUpdater.startUpdate(tenant, thingId, actionId, null, downloadAndUpdateRequest.getSoftwareModules(), + targetSecurityToken, (device, actionId1) -> { + switch (device.getUpdateStatus().getResponseStatus()) { case SUCCESSFUL: spSenderService.finishUpdateProcess( new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), - "Simulation complete!"); + device.getUpdateStatus().getStatusMessages()); break; case ERROR: spSenderService.finishUpdateProcessWithError( new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), - "Simulation complete with error!"); + device.getUpdateStatus().getStatusMessages()); break; default: break; diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java index 2358bf013..1ced8c2fd 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.simulator.amqp; +import java.util.List; import java.util.Map; import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings; @@ -23,13 +24,9 @@ import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; /** - * Sender service to send message to SP. - * - * - * + * Sender service to send messages to update server. */ @Service public class SpSenderService extends SenderService { @@ -59,8 +56,9 @@ public class SpSenderService extends SenderService { * @param description * a description according the update process */ - public void finishUpdateProcess(final SimulatedUpdate update, final String description) { - final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED, description); + public void finishUpdateProcess(final SimulatedUpdate update, final List updateResultMessages) { + final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED, + updateResultMessages); sendMessage(spExchange, updateResultMessage); } @@ -72,9 +70,9 @@ public class SpSenderService extends SenderService { * @param messageDescription * a description according the update process */ - public void finishUpdateProcessWithError(final SimulatedUpdate update, final String messageDescription) { - sendErrorgMessage(update, messageDescription); - LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", messageDescription, + public void finishUpdateProcessWithError(final SimulatedUpdate update, final List updateResultMessages) { + sendErrorgMessage(update, updateResultMessages); + LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", updateResultMessages, update.getThingId()); } @@ -88,8 +86,8 @@ public class SpSenderService extends SenderService { * @param actionId * the ID of the action for the error message */ - public void sendErrorMessage(final String tenant, final String messageDescription, final Long actionId) { - final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, messageDescription, actionId); + public void sendErrorMessage(final String tenant, final List updateResultMessages, final Long actionId) { + final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, updateResultMessages, actionId); sendMessage(spExchange, message); } @@ -101,8 +99,8 @@ public class SpSenderService extends SenderService { * @param warningMessage * a warning description */ - public void sendWarningMessage(final SimulatedUpdate update, final String warningMessage) { - final Message message = createActionStatusMessage(update, warningMessage, ActionStatus.WARNING); + public void sendWarningMessage(final SimulatedUpdate update, final List updateResultMessages) { + final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.WARNING); sendMessage(spExchange, message); } @@ -119,8 +117,8 @@ public class SpSenderService extends SenderService { * the cached value */ public void sendActionStatusMessage(final String tenant, final ActionStatus actionStatus, - final String actionMessage, final Long actionId) { - final Message message = createActionStatusMessage(tenant, actionStatus, actionMessage, actionId); + final List updateResultMessages, final Long actionId) { + final Message message = createActionStatusMessage(tenant, actionStatus, updateResultMessages, actionId); sendMessage(message); } @@ -162,11 +160,11 @@ public class SpSenderService extends SenderService { * * @param context * the current context - * @param messageDescription - * a description according the update process + * @param updateResultMessages + * a list of descriptions according the update process */ - private void sendErrorgMessage(final SimulatedUpdate update, final String messageDescription) { - final Message message = createActionStatusMessage(update, messageDescription, ActionStatus.ERROR); + private void sendErrorgMessage(final SimulatedUpdate update, final List updateResultMessages) { + final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.ERROR); sendMessage(spExchange, message); } @@ -183,7 +181,7 @@ public class SpSenderService extends SenderService { * the cacheValue value */ private Message createActionStatusMessage(final String tenant, final ActionStatus actionStatus, - final String actionMessage, final Long actionId) { + final List updateResultMessages, final Long actionId) { final MessageProperties messageProperties = new MessageProperties(); final Map headers = messageProperties.getHeaders(); final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); @@ -192,15 +190,14 @@ public class SpSenderService extends SenderService { headers.put(MessageHeaderKey.TENANT, tenant); headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON); - if (!StringUtils.isEmpty(actionMessage)) { - actionUpdateStatus.getMessage().add(actionMessage); - } + actionUpdateStatus.getMessage().addAll(updateResultMessages); + actionUpdateStatus.setActionId(actionId); return convertMessage(actionUpdateStatus, messageProperties); } private Message createUpdateResultMessage(final SimulatedUpdate cacheValue, final ActionStatus actionStatus, - final String updateResultMessage) { + final List updateResultMessages) { final MessageProperties messageProperties = new MessageProperties(); final Map headers = messageProperties.getHeaders(); final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); @@ -209,14 +206,14 @@ public class SpSenderService extends SenderService { headers.put(MessageHeaderKey.TENANT, cacheValue.getTenant()); headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON); - actionUpdateStatus.getMessage().add(updateResultMessage); + actionUpdateStatus.getMessage().addAll(updateResultMessages); actionUpdateStatus.setActionId(cacheValue.getActionId()); return convertMessage(actionUpdateStatus, messageProperties); } - private Message createActionStatusMessage(final SimulatedUpdate update, final String messageDescription, + private Message createActionStatusMessage(final SimulatedUpdate update, final List updateResultMessages, final ActionStatus status) { - return createActionStatusMessage(update.getTenant(), status, messageDescription, update.getActionId()); + return createActionStatusMessage(update.getTenant(), status, updateResultMessages, update.getActionId()); } } 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 index 3e34a0fa1..6c18e61ac 100644 --- 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 @@ -13,8 +13,6 @@ 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 { 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 index 28ad0eaa9..455702501 100644 --- 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 @@ -8,21 +8,19 @@ */ 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.UpdateStatus.ResponseStatus; 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; @@ -52,8 +50,6 @@ 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 = "") @@ -153,18 +149,12 @@ public class SimulatorView extends VerticalLayout implements View { @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()); - } - }); + this.getUI().access(() -> devices.forEach(device -> { + final BeanItem item = beanContainer.getItem(device.getId()); + if (item != null) { + item.getItemProperty("nextPollCounterSec").setValue(device.getNextPollCounterSec()); } - }); + })); } /** @@ -176,18 +166,14 @@ public class SimulatorView extends VerticalLayout implements View { @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()); - } - + this.getUI().access(() -> { + 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()); } + }); } @@ -200,29 +186,26 @@ public class SimulatorView extends VerticalLayout implements View { @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); + this.getUI().access(() -> { + final BeanItem item = beanContainer.getItem(device.getId()); + if (item != null) { + item.getItemProperty("progress").setValue(device.getProgress()); + if (device.getProgress() >= 1) { + switch (device.getUpdateStatus().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); } - } + }); } @@ -246,18 +229,15 @@ public class SimulatorView extends VerticalLayout implements View { } 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); - } - } - })); + UI.getCurrent().addWindow( + new GenerateDialog((namePrefix, tenant, amount, pollDelay, basePollUrl, gatewayToken, 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); + } + })); } private Converter createProtocolConverter() { From 16350c5e15395960f884081e70db4e94c8400920 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 3 May 2016 18:34:16 +0200 Subject: [PATCH 07/12] Made URL generator configurable. Signed-off-by: Kai Zimmermann --- .../simulator/DeviceSimulatorUpdater.java | 1 + .../application-cloudsandbox.properties | 4 ++ .../src/main/resources/application.properties | 15 ++++-- .../hawkbit/api/ArtifactUrlHandler.java | 8 +++- .../api/ArtifactUrlHandlerProperties.java | 48 +++++++++++++++++++ .../api/PropertyBasedArtifactUrlHandler.java | 11 +++++ .../amqp/AmqpMessageDispatcherService.java | 28 +++++++---- .../hawkbit/dmf/json/model/ArtifactHash.java | 4 -- .../eclipse/hawkbit/TestConfiguration.java | 2 +- .../controller/DataConversionHelper.java | 38 ++++++++------- 10 files changed, 122 insertions(+), 37 deletions(-) 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 index 12ff7dbd2..3d33b61f8 100644 --- 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 @@ -183,6 +183,7 @@ public class DeviceSimulatorUpdater { final Artifact artifact) { artifact.getUrls().entrySet().forEach(entry -> { switch (entry.getKey()) { + case HTTP: case HTTPS: status.add(downloadUrl(entry.getValue(), targetToken, artifact.getHashes().getSha1())); break; diff --git a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties index ecf71da41..b740c2959 100644 --- a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties +++ b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties @@ -8,3 +8,7 @@ # vaadin.servlet.productionMode=true + +hawkbit.artifact.url.coap.enabled=false +hawkbit.artifact.url.http.enabled=false +hawkbit.artifact.url.https.enabled=true diff --git a/examples/hawkbit-example-app/src/main/resources/application.properties b/examples/hawkbit-example-app/src/main/resources/application.properties index 64661d2ec..6e05b6b5a 100644 --- a/examples/hawkbit-example-app/src/main/resources/application.properties +++ b/examples/hawkbit-example-app/src/main/resources/application.properties @@ -7,15 +7,22 @@ # http://www.eclipse.org/legal/epl-v10.html # +# DDI authentication configuration hawkbit.server.ddi.security.authentication.anonymous.enabled=true -hawkbit.server.ddi.security.authentication.targettoken.enabled=false -hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false +hawkbit.server.ddi.security.authentication.targettoken.enabled=true +hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=true -spring.profiles.active=amqp +# Download URL generation config +hawkbit.artifact.url.coap.enabled=false +hawkbit.artifact.url.http.enabled=true +hawkbit.artifact.url.http.port=8080 +hawkbit.artifact.url.https.enabled=false +## Vaadin configuration vaadin.servlet.productionMode=false -## Configuration for RabbitMQ integration +## Configuration for DMF/RabbitMQ integration +spring.profiles.active=amqp spring.rabbitmq.username=guest spring.rabbitmq.password=guest spring.rabbitmq.virtualHost=/ diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java index 522444961..03492122c 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java @@ -13,7 +13,6 @@ package org.eclipse.hawkbit.api; * URLs to specific artifacts. * */ -@FunctionalInterface public interface ArtifactUrlHandler { /** @@ -34,4 +33,11 @@ public interface ArtifactUrlHandler { */ String getUrl(String controllerId, final Long softwareModuleId, final String filename, final String sha1Hash, final UrlProtocol protocol); + + /** + * @param protocol + * to check support for + * @return true of the handler supports given protocol. + */ + boolean protocolSupported(UrlProtocol protocol); } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java index 33fe8651e..50f3f4cad 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java @@ -78,6 +78,12 @@ public class ArtifactUrlHandlerProperties { * @return the pattern to build the URL. */ String getPattern(); + + /** + * @return true if the {@link ProtocolProperties} is + * enabled. + */ + boolean isEnabled(); } /** @@ -93,6 +99,20 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; + /** + * Enables HTTP URI generation in DDI and DMF. + */ + private boolean enabled = true; + + @Override + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + @Override public String getHostname() { return hostname; @@ -143,6 +163,20 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; + /** + * Enables HTTPS URI generation in DDI and DMF. + */ + private boolean enabled = true; + + @Override + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + @Override public String getHostname() { return hostname; @@ -193,6 +227,20 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}"; + /** + * Enables CoAP URI generation in DMF. + */ + private boolean enabled = true; + + @Override + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + @Override public String getHostname() { return hostname; diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java index 174086613..0072f2fbd 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java @@ -84,4 +84,15 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { return replaceMap; } + @Override + public boolean protocolSupported(final UrlProtocol protocol) { + final String protocolString = protocol.name().toLowerCase(); + final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString); + if (properties == null || properties.getPattern() == null) { + return false; + } + + return properties.isEnabled(); + } + } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java index 32bcb02a5..dae5772e6 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java @@ -155,18 +155,26 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) { final Artifact artifact = new Artifact(); - artifact.getUrls().put(Artifact.UrlProtocol.COAP, - artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), - localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP)); - artifact.getUrls().put(Artifact.UrlProtocol.HTTP, - artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), - localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP)); - artifact.getUrls().put(Artifact.UrlProtocol.HTTPS, - artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), - localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS)); + if (artifactUrlHandler.protocolSupported(UrlProtocol.COAP)) { + artifact.getUrls().put(Artifact.UrlProtocol.COAP, + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP)); + } + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTP)) { + artifact.getUrls().put(Artifact.UrlProtocol.HTTP, + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP)); + } + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTPS)) { + artifact.getUrls().put(Artifact.UrlProtocol.HTTPS, + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS)); + } artifact.setFilename(localArtifact.getFilename()); - artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), null)); + artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), localArtifact.getMd5Hash())); artifact.setSize(localArtifact.getSize()); return artifact; } diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java index 5ddb48e4f..6f86fe4a4 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java @@ -13,10 +13,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * JSON representation of artifact hash. - * - * - * - * */ public class ArtifactHash { diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java index 70372fac2..d96856557 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java @@ -79,7 +79,7 @@ public class TestConfiguration implements AsyncConfigurer { } /** - * Bean for the downlod id cache. + * Bean for the download id cache. * * @return the cache */ diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java index e035c47ee..15c2592df 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java @@ -31,7 +31,6 @@ import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactHash; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.Link; import com.google.common.base.Charsets; @@ -40,10 +39,6 @@ import com.google.common.base.Charsets; * Utility class for the Controller API. */ public final class DataConversionHelper { - - @Autowired - ArtifactUrlHandler artifactUrlHandler; - // utility class, private constructor. private DataConversionHelper() { @@ -55,7 +50,6 @@ public final class DataConversionHelper { .map(module -> new Chunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(), module.getName(), createArtifacts(targetid, module, artifactUrlHandler))) .collect(Collectors.toList()); - } private static String mapChunkLegacyKeys(final String key) { @@ -76,29 +70,39 @@ public final class DataConversionHelper { * of the target * @param module * the software module + * * @return a list of artifacts or a empty list. Cannot be . */ public static List createArtifacts(final String targetid, final org.eclipse.hawkbit.repository.model.SoftwareModule module, final ArtifactUrlHandler artifactUrlHandler) { final List files = new ArrayList<>(); - module.getLocalArtifacts().forEach(artifact -> { - final Artifact file = new Artifact(); - file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); - file.setFilename(artifact.getFilename()); - file.setSize(artifact.getSize()); + module.getLocalArtifacts() + .forEach(artifact -> files.add(createArtifact(targetid, artifactUrlHandler, artifact))); + return files; + } + + private static Artifact createArtifact(final String targetid, final ArtifactUrlHandler artifactUrlHandler, + final LocalArtifact artifact) { + final Artifact file = new Artifact(); + file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); + file.setFilename(artifact.getFilename()); + file.setSize(artifact.getSize()); + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTP)) { final String linkHttp = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(), artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTP); + file.add(new Link(linkHttp).withRel("download-http")); + file.add(new Link(linkHttp + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum-http")); + } + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTPS)) { final String linkHttps = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(), artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTPS); file.add(new Link(linkHttps).withRel("download")); file.add(new Link(linkHttps + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum")); - file.add(new Link(linkHttp).withRel("download-http")); - file.add(new Link(linkHttp + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum-http")); - - files.add(file); - }); - return files; + } + return file; } static ControllerBase fromTarget(final Target target, final List actions, From ffece302de197fa587a0932e1e35169c5433da26 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Wed, 4 May 2016 08:28:11 +0200 Subject: [PATCH 08/12] https config for cloud. Signed-off-by: Kai Zimmermann --- .../src/main/resources/application-cloudsandbox.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties index b740c2959..a0cad4e9b 100644 --- a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties +++ b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties @@ -12,3 +12,5 @@ vaadin.servlet.productionMode=true hawkbit.artifact.url.coap.enabled=false hawkbit.artifact.url.http.enabled=false hawkbit.artifact.url.https.enabled=true +hawkbit.artifact.url.https.pattern={protocol}://{hostname}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} +hawkbit.artifact.url.https.hostname=hawkbit.eu-gb.mybluemix.net \ No newline at end of file From 6df949bf2b050f0fc115e3c9cde1c87b99afedcf Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Wed, 4 May 2016 12:22:19 +0200 Subject: [PATCH 09/12] Set sw version also if modules empty. Signed-off-by: Kai Zimmermann --- .../org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 3d33b61f8..43474b9a9 100644 --- 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 @@ -100,7 +100,7 @@ public class DeviceSimulatorUpdater { device.setProgress(0.0); - if (modules == null) { + if (modules == null || modules.isEmpty()) { device.setSwversion(swVersion); } else { device.setSwversion(modules.stream().map(sm -> sm.getModuleVersion()).collect(Collectors.joining(", "))); From 0014dc6302b00aae52f3abbe23d806ee648af10a Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Wed, 4 May 2016 12:22:49 +0200 Subject: [PATCH 10/12] Removed accidental addition of scala dependency. Signed-off-by: Kai Zimmermann --- examples/hawkbit-device-simulator/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/hawkbit-device-simulator/pom.xml b/examples/hawkbit-device-simulator/pom.xml index 33d165584..728fe0595 100644 --- a/examples/hawkbit-device-simulator/pom.xml +++ b/examples/hawkbit-device-simulator/pom.xml @@ -133,11 +133,6 @@ spring-boot-configuration-processor true - - org.scala-lang - scala-library - 2.10.4 - org.apache.httpcomponents httpclient From 5144f78c2b26c7df1032da54eae865827b4e9a3c Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Mon, 9 May 2016 10:50:14 +0200 Subject: [PATCH 11/12] Improved code readability. Signed-off-by: Kai Zimmermann --- .../simulator/DeviceSimulatorUpdater.java | 16 ++- .../hawkbit/simulator/UpdateStatus.java | 28 ++++- .../hawkbit/simulator/ui/SimulatorView.java | 105 +++++++++++------- .../hawkbit/controller/RootController.java | 6 +- 4 files changed, 104 insertions(+), 51 deletions(-) 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 index 43474b9a9..6f640ca53 100644 --- 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 @@ -138,7 +138,7 @@ public class DeviceSimulatorUpdater { public void run() { if (device.getProgress() <= 0 && modules != null) { device.setUpdateStatus(simulateDownloads(device.getTargetSecurityToken())); - if (device.getUpdateStatus().getResponseStatus().equals(ResponseStatus.ERROR)) { + if (isErrorResponse(device.getUpdateStatus())) { callback.updateFinished(device, actionId); eventbus.post(new ProgressUpdate(device)); return; @@ -169,7 +169,7 @@ public class DeviceSimulatorUpdater { result.getStatusMessages().add("Simulation complete!"); status.forEach(download -> { result.getStatusMessages().addAll(download.getStatusMessages()); - if (download.getResponseStatus().equals(ResponseStatus.ERROR)) { + if (isErrorResponse(download)) { result.setResponseStatus(ResponseStatus.ERROR); } }); @@ -179,6 +179,14 @@ public class DeviceSimulatorUpdater { return result; } + private boolean isErrorResponse(final UpdateStatus status) { + if (status == null) { + return false; + } + + return ResponseStatus.ERROR.equals(status.getResponseStatus()); + } + private static void handleArtifacts(final String targetToken, final List status, final Artifact artifact) { artifact.getUrls().entrySet().forEach(entry -> { @@ -195,7 +203,7 @@ public class DeviceSimulatorUpdater { } private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash) { - LOGGER.debug("Downloading " + url); + LOGGER.debug("Downloading {}", url); long overallread = 0; try { @@ -245,7 +253,7 @@ public class DeviceSimulatorUpdater { /** * 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. * + * send the result back to the hawkBit update server. */ @FunctionalInterface public interface UpdaterCallback { diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java index 49e9947d7..f4e1f75a7 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java @@ -16,15 +16,30 @@ import java.util.List; * */ public class UpdateStatus { - private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL; - private final List statusMessages = new ArrayList<>(); + private ResponseStatus responseStatus; + private List statusMessages; + /** + * Constructor. + * + * @param responseStatus + * of the update + */ public UpdateStatus(final ResponseStatus responseStatus) { this.responseStatus = responseStatus; } + /** + * Constructor including status message. + * + * @param responseStatus + * of the update + * @param message + * of the update status + */ public UpdateStatus(final ResponseStatus responseStatus, final String message) { this(responseStatus); + statusMessages = new ArrayList<>(); statusMessages.add(message); } @@ -37,6 +52,10 @@ public class UpdateStatus { } public List getStatusMessages() { + if (statusMessages == null) { + statusMessages = new ArrayList<>(); + } + return statusMessages; } @@ -46,11 +65,12 @@ public class UpdateStatus { */ public enum ResponseStatus { /** - * updated has been successful and response the successful update. + * Update has been successful and response the successful update. */ SUCCESSFUL, + /** - * updated has been not successful and response the error update. + * Update has been not successful and response the error update. */ ERROR; } 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 index 455702501..bd6ecbe8b 100644 --- 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 @@ -55,6 +55,22 @@ import com.vaadin.ui.renderers.ProgressBarRenderer; @SpringView(name = "") public class SimulatorView extends VerticalLayout implements View { + private static final String NEXT_POLL_COUNTER_SEC_COL = "nextPollCounterSec"; + + private static final String RESPONSE_STATUS_COL = "responseStatus"; + + private static final String PROTOCOL_COL = "protocol"; + + private static final String TENANT_COL = "tenant"; + + private static final String PROGRESS_COL = "progress"; + + private static final String SWVERSION_COL = "swversion"; + + private static final String STATUS_COL = "status"; + + private static final String ID_COL = "id"; + private static final long serialVersionUID = 1L; @Autowired @@ -75,6 +91,7 @@ public class SimulatorView extends VerticalLayout implements View { private BeanContainer beanContainer; + @SuppressWarnings("unchecked") @Override public void enter(final ViewChangeEvent event) { eventbus.register(this); @@ -87,7 +104,7 @@ public class SimulatorView extends VerticalLayout implements View { createToolbar(); beanContainer = new BeanContainer<>(AbstractSimulatedDevice.class); - beanContainer.setBeanIdProperty("id"); + beanContainer.setBeanIdProperty(ID_COL); grid.setSizeFull(); grid.setCellStyleGenerator(new CellStyleGenerator() { @@ -96,28 +113,28 @@ public class SimulatorView extends VerticalLayout implements View { @Override public String getStyle(final CellReference cellReference) { - return cellReference.getPropertyId().equals("status") ? "centeralign" : null; + return cellReference.getPropertyId().equals(STATUS_COL) ? "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"); + grid.appendHeaderRow().getCell(RESPONSE_STATUS_COL).setComponent(responseComboBox); + grid.setColumnOrder(ID_COL, STATUS_COL, SWVERSION_COL, PROGRESS_COL, TENANT_COL, PROTOCOL_COL, + RESPONSE_STATUS_COL, NEXT_POLL_COUNTER_SEC_COL); // header widths - grid.getColumn("status").setMaximumWidth(80); - grid.getColumn("protocol").setMaximumWidth(180); - grid.getColumn("responseStatus").setMaximumWidth(240); - grid.getColumn("nextPollCounterSec").setMaximumWidth(210); + grid.getColumn(STATUS_COL).setMaximumWidth(80); + grid.getColumn(PROTOCOL_COL).setMaximumWidth(180); + grid.getColumn(RESPONSE_STATUS_COL).setMaximumWidth(240); + grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).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(createProtocolConverter()); - grid.getColumn("status").setRenderer(new HtmlRenderer(), createStatusConverter()); - grid.removeColumn("tenant"); + grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).setHeaderCaption("Next Poll in (sec)"); + grid.getColumn(SWVERSION_COL).setHeaderCaption("SW Version"); + grid.getColumn(RESPONSE_STATUS_COL).setHeaderCaption("Response Update Status"); + grid.getColumn(PROGRESS_COL).setRenderer(new ProgressBarRenderer()); + grid.getColumn(PROTOCOL_COL).setConverter(createProtocolConverter()); + grid.getColumn(STATUS_COL).setRenderer(new HtmlRenderer(), createStatusConverter()); + grid.removeColumn(TENANT_COL); // grid combobox responseComboBox.setItemIcon(ResponseStatus.SUCCESSFUL, FontAwesome.CHECK_CIRCLE); @@ -125,8 +142,8 @@ public class SimulatorView extends VerticalLayout implements View { responseComboBox.setNullSelectionAllowed(false); responseComboBox.setValue(ResponseStatus.SUCCESSFUL); responseComboBox.addValueChangeListener(valueChangeEvent -> { - beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus") - .setValue(valueChangeEvent.getProperty().getValue())); + beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId) + .getItemProperty(RESPONSE_STATUS_COL).setValue(valueChangeEvent.getProperty().getValue())); }); // add all components @@ -137,7 +154,7 @@ public class SimulatorView extends VerticalLayout implements View { setExpandRatio(grid, 1.0F); // load beans - repository.getAll().forEach(device -> beanContainer.addBean(device)); + repository.getAll().forEach(beanContainer::addBean); } @Override @@ -146,13 +163,14 @@ public class SimulatorView extends VerticalLayout implements View { eventbus.unregister(this); } + @SuppressWarnings("unchecked") @Subscribe public void pollCounterUpdate(final NextPollCounterUpdate update) { final List devices = update.getDevices(); this.getUI().access(() -> devices.forEach(device -> { final BeanItem item = beanContainer.getItem(device.getId()); if (item != null) { - item.getItemProperty("nextPollCounterSec").setValue(device.getNextPollCounterSec()); + item.getItemProperty(NEXT_POLL_COUNTER_SEC_COL).setValue(device.getNextPollCounterSec()); } })); } @@ -163,17 +181,19 @@ public class SimulatorView extends VerticalLayout implements View { * @param update * the update event posted on the event bus */ + @SuppressWarnings("unchecked") @Subscribe public void initUpdate(final InitUpdate update) { final AbstractSimulatedDevice device = update.getDevice(); this.getUI().access(() -> { 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()); + if (item == null) { + return; } + item.getItemProperty(PROGRESS_COL).setValue(device.getProgress()); + item.getItemProperty(STATUS_COL).setValue(Status.PEDNING); + item.getItemProperty(SWVERSION_COL).setValue(device.getSwversion()); }); } @@ -183,32 +203,37 @@ public class SimulatorView extends VerticalLayout implements View { * @param update * the update event posted on the event bus */ + @SuppressWarnings("unchecked") @Subscribe public void progessUpdate(final ProgressUpdate update) { final AbstractSimulatedDevice device = update.getDevice(); this.getUI().access(() -> { final BeanItem item = beanContainer.getItem(device.getId()); if (item != null) { - item.getItemProperty("progress").setValue(device.getProgress()); - if (device.getProgress() >= 1) { - switch (device.getUpdateStatus().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); - } + item.getItemProperty(PROGRESS_COL).setValue(device.getProgress()); + setStatusColumn(device, item); } - }); } + @SuppressWarnings("unchecked") + private void setStatusColumn(final AbstractSimulatedDevice device, final BeanItem item) { + if (device.getProgress() >= 1) { + switch (device.getUpdateStatus().getResponseStatus()) { + case SUCCESSFUL: + item.getItemProperty(STATUS_COL).setValue(Status.FINISH); + break; + case ERROR: + item.getItemProperty(STATUS_COL).setValue(Status.ERROR); + break; + default: + item.getItemProperty(STATUS_COL).setValue(Status.UNKNWON); + } + } else { + item.getItemProperty(STATUS_COL).setValue(Status.PEDNING); + } + } + private void createToolbar() { final Button createDevicesButton = new Button("generate..."); createDevicesButton.setIcon(FontAwesome.GEARS); diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java index 000e1e2e5..14383f30b 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java @@ -220,7 +220,7 @@ public class RootController { + " of: " + request.getRequestURI()); } else { statusMessage.addMessage( - ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI()); + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI()); } controllerManagement.addActionStatusMessage(statusMessage); return action; @@ -390,7 +390,7 @@ public class RootController { LOG.debug("Controller confirmed cancel (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.CANCELED); - actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target confirmed cancelation"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target confirmed cancelation."); break; case REJECTED: LOG.info("Controller reported internal error (actionid: {}, targetid: {}) as we got {} report.", actionid, @@ -424,7 +424,7 @@ public class RootController { targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.RUNNING); actionStatus.addMessage( - ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported: " + feedback.getStatus().getExecution()); + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported " + feedback.getStatus().getExecution()); } private static void handleClosedUpdateStatus(final ActionFeedback feedback, final String targetid, From c2413ebd61a2ddb9525bb7b1ca43b6b0c25c1ccf Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Mon, 9 May 2016 11:23:42 +0200 Subject: [PATCH 12/12] Added tests for md5 has gen in download messages. Signed-off-by: Kai Zimmermann --- .../amqp/AmqpMessageDispatcherServiceTest.java | 17 +++++++++++++++-- .../amqp/AmqpMessageHandlerServiceTest.java | 8 +++++--- .../hawkbit/amqp/BaseAmqpServiceTest.java | 2 ++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java index 4e0852ff3..c5cea9e05 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java @@ -8,8 +8,8 @@ */ package org.eclipse.hawkbit.amqp; +import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -23,6 +23,7 @@ import static org.mockito.Mockito.when; import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.TestDataUtil; @@ -159,7 +160,19 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit if (!softwareModule.getModuleId().equals(module.getId())) { continue; } - assertFalse("The software module artifacts should not be empty", softwareModule.getArtifacts().isEmpty()); + assertThat(softwareModule.getArtifacts().size()).isEqualTo(module.getArtifacts().size()).isGreaterThan(0); + + module.getArtifacts().forEach(dbArtifact -> { + final Optional found = softwareModule.getArtifacts() + .stream().filter(dmfartifact -> dmfartifact.getFilename() + .equals(((LocalArtifact) dbArtifact).getFilename())) + .findFirst(); + + assertTrue("The artifact should exist in message", found.isPresent()); + assertThat(found.get().getSize()).isEqualTo(dbArtifact.getSize()); + assertThat(found.get().getHashes().getMd5()).isEqualTo(dbArtifact.getMd5Hash()); + assertThat(found.get().getHashes().getSha1()).isEqualTo(dbArtifact.getSha1Hash()); + }); } } diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java index 18ee0bde4..3051e4e22 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java @@ -333,6 +333,8 @@ public class AmqpMessageHandlerServiceTest { assertThat(downloadResponse.getResponseCode()).as("Message body response code is wrong") .isEqualTo(HttpStatus.OK.value()); assertThat(downloadResponse.getArtifact().getSize()).as("Wrong artifact size in message body").isEqualTo(1L); + assertThat(downloadResponse.getArtifact().getHashes().getSha1()).as("Wrong sha1 hash").isEqualTo("sha1"); + assertThat(downloadResponse.getArtifact().getHashes().getMd5()).as("Wrong md5 hash").isEqualTo("md5"); assertThat(downloadResponse.getDownloadUrl()).as("download url is wrong") .startsWith("http://localhost/api/v1/downloadserver/downloadId/"); } @@ -381,7 +383,7 @@ public class AmqpMessageHandlerServiceTest { } private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status) { - return createActionUpdateStatus(status, 2l); + return createActionUpdateStatus(status, 2L); } private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status, final Long id) { @@ -406,7 +408,7 @@ public class AmqpMessageHandlerServiceTest { } private List createSoftwareModuleList() { - final List softwareModuleList = new ArrayList(); + final List softwareModuleList = new ArrayList<>(); final SoftwareModule softwareModule = new SoftwareModule(); softwareModule.setId(777L); softwareModuleList.add(softwareModule); @@ -428,7 +430,7 @@ public class AmqpMessageHandlerServiceTest { return action; } - private void initalizeSecurityTokenGenerator() throws IllegalArgumentException, IllegalAccessException { + private void initalizeSecurityTokenGenerator() throws IllegalAccessException { final SecurityTokenGeneratorHolder instance = SecurityTokenGeneratorHolder.getInstance(); final Field[] fields = instance.getClass().getDeclaredFields(); for (final Field field : fields) { diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java index 0bd8c164b..20d03bdd6 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java @@ -52,6 +52,8 @@ public class BaseAmqpServiceTest { final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); actionUpdateStatus.setActionId(1L); actionUpdateStatus.setSoftwareModuleId(2L); + actionUpdateStatus.getMessage().add("Message 1"); + actionUpdateStatus.getMessage().add("Message 2"); final Message message = rabbitTemplate.getMessageConverter().toMessage(actionUpdateStatus, new MessageProperties());