diff --git a/examples/hawkbit-device-simulator/README.md b/examples/hawkbit-device-simulator/README.md index 1ba29bb7e..0d73f3f3f 100644 --- a/examples/hawkbit-device-simulator/README.md +++ b/examples/hawkbit-device-simulator/README.md @@ -24,6 +24,12 @@ The simulator has user authentication enabled in **cloud profile**. Default cred This can be configured/disabled by spring boot properties +## hawkBit APIs + +The simulator supports `DDI` as well as the `DMF` integration APIs. +In case there is no AMQP message broker (like rabbitMQ) running, you can disable the AMQP support for the device simulator, so the simulator is not trying to connect to an amqp message broker. +Configuration property `hawkbit.device.simulator.amqp.enabled=true` + ## Usage ### Graphical User Interface diff --git a/examples/hawkbit-device-simulator/cf/manifest.yml b/examples/hawkbit-device-simulator/cf/manifest.yml index 51a43ace6..188ef7780 100644 --- a/examples/hawkbit-device-simulator/cf/manifest.yml +++ b/examples/hawkbit-device-simulator/cf/manifest.yml @@ -17,6 +17,4 @@ applications: services: - dmf-rabbit env: - SPRING_PROFILES_ACTIVE: cloud,amqp - CF_STAGING_TIMEOUT: 15 - CF_STARTUP_TIMEOUT: 15 + SPRING_PROFILES_ACTIVE: cloud 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 8d5c5e0b1..3a8690cb3 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 @@ -72,6 +72,7 @@ public class SimulatedDeviceFactory { final int pollDelaySec, final URL baseEndpoint, final String gatewayToken) { switch (protocol) { case DMF_AMQP: + spSenderService.createOrUpdateThing(tenant, id); return new DMFSimulatedDevice(id, tenant, spSenderService, pollDelaySec); case DDI_HTTP: final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger()) diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java index 43f954c00..b100cb28f 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulationController.java @@ -8,11 +8,13 @@ */ package org.eclipse.hawkbit.simulator; +import static org.eclipse.hawkbit.simulator.amqp.AmqpProperties.CONFIGURATION_PREFIX; + import java.net.MalformedURLException; import java.net.URL; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; -import org.eclipse.hawkbit.simulator.amqp.SpSenderService; +import org.eclipse.hawkbit.simulator.amqp.AmqpProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,22 +23,19 @@ import org.springframework.web.bind.annotation.RestController; /** * REST endpoint for controlling the device simulator. - * - * - * */ @RestController public class SimulationController { - @Autowired - private SpSenderService spSenderService; - @Autowired private DeviceSimulatorRepository repository; @Autowired private SimulatedDeviceFactory deviceFactory; + @Autowired + private AmqpProperties amqpProperties; + /** * The start resource to start a device creation. * @@ -82,6 +81,12 @@ public class SimulationController { return ResponseEntity.badRequest().body("query param api only allows value of 'dmf' or 'ddi'"); } + if (protocol == Protocol.DMF_AMQP && isDmfDisabled()) { + return ResponseEntity.badRequest() + .body("The AMQP interface has been disabled, to use DMF protocol you need to enable the AMQP interface via '" + + CONFIGURATION_PREFIX + ".enabled=true'"); + } + for (int i = 0; i < amount; i++) { final String deviceId = name + i; repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint), @@ -90,4 +95,8 @@ public class SimulationController { return ResponseEntity.ok("Updated " + amount + " DMF connected targets!"); } + + private boolean isDmfDisabled() { + return !amqpProperties.isEnabled(); + } } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java index 486eb4b5e..69ff765d0 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatorStartup.java @@ -11,7 +11,7 @@ package org.eclipse.hawkbit.simulator; import java.net.MalformedURLException; import java.net.URL; -import org.eclipse.hawkbit.simulator.amqp.SpSenderService; +import org.eclipse.hawkbit.simulator.amqp.AmqpProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -32,24 +32,27 @@ public class SimulatorStartup implements ApplicationListener { for (int i = 0; i < autostart.getAmount(); i++) { final String deviceId = autostart.getName() + i; try { - repository.add(deviceFactory.createSimulatedDevice(deviceId, autostart.getTenant(), - autostart.getApi(), autostart.getPollDelay(), new URL(autostart.getEndpoint()), - autostart.getGatewayToken())); + if (amqpProperties.isEnabled()) { + repository.add(deviceFactory.createSimulatedDevice(deviceId, autostart.getTenant(), + autostart.getApi(), autostart.getPollDelay(), new URL(autostart.getEndpoint()), + autostart.getGatewayToken())); + } + } catch (final MalformedURLException e) { LOGGER.error("Creation of simulated device at startup failed.", e); } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java index edaf9d11a..5e9b3e049 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.simulator.amqp; +import static org.eclipse.hawkbit.simulator.amqp.AmqpProperties.CONFIGURATION_PREFIX; + import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -27,6 +29,7 @@ import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.amqp.RabbitProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -39,6 +42,7 @@ import org.springframework.retry.support.RetryTemplate; */ @Configuration @EnableConfigurationProperties(AmqpProperties.class) +@ConditionalOnProperty(prefix = CONFIGURATION_PREFIX, name = "enabled") public class AmqpConfiguration { private static final Logger LOGGER = LoggerFactory.getLogger(AmqpConfiguration.class); diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java index 8fba3ac5b..3730a3350 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java @@ -19,6 +19,17 @@ import org.springframework.stereotype.Component; @Component @ConfigurationProperties("hawkbit.device.simulator.amqp") public class AmqpProperties { + + /** + * The prefix for this configuration. + */ + public static final String CONFIGURATION_PREFIX = "hawkbit.device.simulator.amqp"; + + /** + * Indicates if the AMQP interface is enabled for the device simulator. + */ + private boolean enabled; + /** * Queue for receiving DMF messages from update server. */ @@ -84,4 +95,12 @@ public class AmqpProperties { public void setDeadLetterTtl(final int deadLetterTtl) { this.deadLetterTtl = deadLetterTtl; } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } } 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 7d55fb375..8dac6d4bc 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 @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.simulator.amqp; +import static org.eclipse.hawkbit.simulator.amqp.AmqpProperties.CONFIGURATION_PREFIX; + import java.util.Map; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; @@ -22,6 +24,7 @@ import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; @@ -32,6 +35,7 @@ import com.google.common.collect.Lists; * */ @Component +@ConditionalOnProperty(prefix = CONFIGURATION_PREFIX, name = "enabled") public class SpReceiverService extends ReceiverService { private static final Logger LOGGER = LoggerFactory.getLogger(ReceiverService.class); diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java index b50098829..6d1806463 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/GenerateDialog.java @@ -52,6 +52,7 @@ public class GenerateDialog extends Window { private final TextField gatewayTokenTextField; private OptionGroup protocolGroup; private Button buttonOk; + private final boolean dmfEnabled; /** * Creates a new pop window for setting the configuration of simulating @@ -60,9 +61,12 @@ public class GenerateDialog extends Window { * @param callback * the callback which is called when the dialog has been * successfully confirmed. + * @param dmfEnabled + * indicates if the AMQP/DMF interface is enabled by + * configuration and if the option DMF should be enabled or not */ - public GenerateDialog(final GenerateDialogCallback callback) { - + public GenerateDialog(final GenerateDialogCallback callback, final boolean dmfEnabled) { + this.dmfEnabled = dmfEnabled; formLayout.setSpacing(true); formLayout.setMargin(true); @@ -187,15 +191,19 @@ public class GenerateDialog extends Window { this.protocolGroup = new OptionGroup("Simulated Device Protocol"); protocolGroup.addItem(Protocol.DMF_AMQP); protocolGroup.addItem(Protocol.DDI_HTTP); + protocolGroup.select(Protocol.DMF_AMQP); protocolGroup.setItemCaption(Protocol.DMF_AMQP, "Device Management Federation API (AMQP push)"); protocolGroup.setItemCaption(Protocol.DDI_HTTP, "Direct Device Interface (HTTP poll)"); protocolGroup.setNullSelectionAllowed(false); - protocolGroup.select(Protocol.DMF_AMQP); protocolGroup.addValueChangeListener(event -> { final boolean directDeviceOptionSelected = event.getProperty().getValue().equals(Protocol.DDI_HTTP); pollUrlTextField.setVisible(directDeviceOptionSelected); gatewayTokenTextField.setVisible(directDeviceOptionSelected); }); + protocolGroup.setItemEnabled(Protocol.DMF_AMQP, dmfEnabled); + if (!dmfEnabled) { + protocolGroup.select(Protocol.DDI_HTTP); + } } private void createOkButton(final GenerateDialogCallback callback) { 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 686945407..4a81547c5 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 @@ -17,6 +17,7 @@ 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.AmqpProperties; import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.event.InitUpdate; import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate; @@ -90,6 +91,9 @@ public class SimulatorView extends VerticalLayout implements View { @Autowired private transient EventBus eventbus; + @Autowired + private transient AmqpProperties amqpProperties; + private final Label caption = new Label("DMF/DDI Simulated Devices"); private final HorizontalLayout toolbar = new HorizontalLayout(); private final Grid grid = new Grid(); @@ -266,9 +270,8 @@ public class SimulatorView extends VerticalLayout implements View { final String deviceId = namePrefix + index; beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken))); - spSenderService.createOrUpdateThing(tenant, deviceId); } - })); + }, amqpProperties.isEnabled())); } private ProtocolConverter createProtocolConverter() { diff --git a/examples/hawkbit-device-simulator/src/main/resources/application.properties b/examples/hawkbit-device-simulator/src/main/resources/application.properties index 5d3f04be7..60fa817e2 100644 --- a/examples/hawkbit-device-simulator/src/main/resources/application.properties +++ b/examples/hawkbit-device-simulator/src/main/resources/application.properties @@ -8,6 +8,7 @@ # ## Configuration for DMF communication +hawkbit.device.simulator.amqp.enabled=true hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp=simulator_receiver hawkbit.device.simulator.amqp.deadLetterQueue=simulator_deadletter hawkbit.device.simulator.amqp.deadLetterExchange=simulator.deadletter diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index 1784606bd..d8a6f54fe 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -281,6 +281,16 @@ public interface DistributionSetManagement { Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, @NotNull Pageable pageable); + /** + * Finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @return list of distributionSetMetadata for a given distribution set Id. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId); + /** * finds all meta data by the given distribution set id. * diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java index bc3c50004..03027598e 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -483,5 +483,23 @@ public interface SoftwareManagement { */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm); + + /** + * Finds all meta data by the given software module id. + * + * @param softwareModuleId + * the software module id to retrieve the meta data from + + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + * @return result of all meta data entries for a given software + * module id. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findSoftwareModuleMetadataBySoftwareModuleId(Long softwareModuleId); } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionCreatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionCreatedEvent.java new file mode 100644 index 000000000..20515521d --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionCreatedEvent.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.repository.model.DistributionSet; + +/** + * Defines the {@link AbstractBaseEntityEvent} of creating a new {@link DistributionSet}. + * + */ +public class DistributionCreatedEvent extends AbstractBaseEntityEvent { + + private static final long serialVersionUID = 1L; + + /** + * @param distributionSet + * the distributionSet which has been created + */ + public DistributionCreatedEvent(final DistributionSet distributionSet) { + super(distributionSet); + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java new file mode 100644 index 000000000..47c8c8435 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; +import org.eclipse.hawkbit.repository.model.DistributionSet; + +/** + * Defines the {@link AbstractDistributedEvent} for deletion of + * {@link DistributionSet}. + */ +public class DistributionDeletedEvent extends AbstractDistributedEvent { + private static final long serialVersionUID = -3308850381757843098L; + private final Long distributionId; + + /** + * @param tenant + * the tenant for this event + * @param distributionId + * the ID of the distribution set which has been deleted + */ + public DistributionDeletedEvent(final String tenant, final Long distributionId) { + super(-1, tenant); + this.distributionId = distributionId; + } + + public Long getDistributionSetId() { + return distributionId; + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetUpdateEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetUpdateEvent.java new file mode 100644 index 000000000..d060e2ee5 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetUpdateEvent.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.repository.model.DistributionSet; + +/** + * Defines the {@link AbstractBaseEntityEvent} for update a {@link DistributionSet}. + * + */ +public class DistributionSetUpdateEvent extends AbstractBaseEntityEvent { + + private static final long serialVersionUID = 1L; + + + /** + * Constructor + * @param ds Distribution Set + */ + public DistributionSetUpdateEvent(final DistributionSet ds) { + super(ds); + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetDeletedEvent.java new file mode 100644 index 000000000..637a0dcc5 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetDeletedEvent.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; +import org.eclipse.hawkbit.repository.model.Target; + +/** + * + * Defines the {@link AbstractBaseEntityEvent} of deleting a {@link Target}. + */ +public class TargetDeletedEvent extends AbstractDistributedEvent { + + private static final long serialVersionUID = 1L; + private final long targetId; + + /** + * @param tenant + * the tenant for this event + * @param targetId + * the ID of the target which has been deleted + */ + public TargetDeletedEvent(final String tenant, final long targetId) { + super(-1, tenant); + this.targetId = targetId; + } + + /** + * @return the targetId + */ + public long getTargetId() { + return targetId; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java new file mode 100644 index 000000000..8ae5718e9 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.eventbus.event; + +import org.eclipse.hawkbit.repository.model.Target; + +/** + * Defines the {@link AbstractBaseEntityEvent} of updating a {@link Target}. + * + */ +public class TargetUpdatedEvent extends AbstractBaseEntityEvent { + + private static final long serialVersionUID = 5665118668865832477L; + + /** + * Constructor + * + * @param baseEntity + * Target entity + */ + public TargetUpdatedEvent(final Target baseEntity) { + super(baseEntity); + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 0e97d6ff5..8736fefd7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -28,6 +28,7 @@ import org.eclipse.hawkbit.repository.DistributionSetMetadataFields; import org.eclipse.hawkbit.repository.DistributionSetTypeFields; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.TagManagement; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagAssigmentResultEvent; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityLockedException; @@ -54,6 +55,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -102,6 +104,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; + @Autowired + private TenantAware tenantAware; + @Override public DistributionSet findDistributionSetByIdWithDetails(final Long distid) { return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid)); @@ -193,6 +198,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { // handle the empty list distributionSetRepository.deleteByIdIn(toHardDelete); } + + Arrays.stream(distributionSetIDs) + .forEach(dsId -> eventBus.post(new DistributionDeletedEvent(tenantAware.getCurrentTenant(), dsId))); } @Override @@ -475,11 +483,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { if (distributionSetMetadataRepository.exists(metadata.getId())) { throwMetadataKeyAlreadyExists(metadata.getId().getKey()); } - // merge base distribution set so optLockRevision gets updated and audit - // log written because - // modifying metadata is modifying the base distribution set itself for - // auditing purposes. - entityManager.merge((JpaDistributionSet) metadata.getDistributionSet()).setLastModifiedAt(0L); + + touch(metadata.getDistributionSet()); return distributionSetMetadataRepository.save(metadata); } @@ -494,7 +499,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { for (final JpaDistributionSetMetadata distributionSetMetadata : metadata) { checkAndThrowAlreadyIfDistributionSetMetadataExists(distributionSetMetadata.getId()); } - metadata.forEach(m -> entityManager.merge((JpaDistributionSet) m.getDistributionSet()).setLastModifiedAt(0L)); + metadata.forEach(m -> touch(m.getDistributionSet())); return new ArrayList<>( (Collection) distributionSetMetadataRepository.save(metadata)); @@ -510,7 +515,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { findOne(metadata.getDistributionSet(), metadata.getKey()); // touch it to update the lock revision because we are modifying the // DS indirectly - entityManager.merge((JpaDistributionSet) metadata.getDistributionSet()).setLastModifiedAt(0L); + touch(metadata.getDistributionSet());; return distributionSetMetadataRepository.save(metadata); } @@ -518,13 +523,26 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying public void deleteDistributionSetMetadata(final DistributionSet distributionSet, final String key) { + touch(distributionSet); distributionSetMetadataRepository.delete(new DsMetadataCompositeKey(distributionSet, key)); } + /** + * Method to get the latest distribution set based on ds ID after the metadata changes for that distribution set. + * @param distributionSet Distribution set + */ + private void touch(final DistributionSet distributionSet) { + final DistributionSet latestDistributionSet = findDistributionSetById(distributionSet.getId()); + // merge base distribution set so optLockRevision gets updated and audit + // log written because + // modifying metadata is modifying the base distribution set itself for + // auditing purposes. + entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L); + } + @Override public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, final Pageable pageable) { - return convertMdPage(distributionSetMetadataRepository .findAll((Specification) (root, query, cb) -> cb.equal( root.get(JpaDistributionSetMetadata_.distributionSet).get(JpaDistributionSet_.id), @@ -532,6 +550,14 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { pageable); } + @Override + public List findDistributionSetMetadataByDistributionSetId(final Long distributionSetId) { + return new ArrayList(distributionSetMetadataRepository + .findAll((Specification) (root, query, cb) -> cb.equal( + root.get(JpaDistributionSetMetadata_.distributionSet).get(JpaDistributionSet_.id), + distributionSetId))); + } + @Override public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, final String rsqlParam, final Pageable pageable) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index b561667a9..3f8c1a54b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -621,6 +621,16 @@ public class JpaSoftwareManagement implements SoftwareManagement { pageable); } + @Override + public List findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId) { + return new ArrayList<>( + softwareModuleMetadataRepository + .findAll((Specification) (root, query, + cb) -> cb.and(cb.equal( + root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id), + softwareModuleId)))); + } + @Override public SoftwareModuleMetadata findSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { return findSoftwareModuleMetadata(new SwMetadataCompositeKey(softwareModule, key)); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 1cd2ffc3c..225c0b4b2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -29,6 +29,7 @@ import javax.persistence.criteria.Root; import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetTagAssigmentResultEvent; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; @@ -48,6 +49,7 @@ import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.data.domain.Page; @@ -94,6 +96,9 @@ public class JpaTargetManagement implements TargetManagement { @Autowired private EventBus eventBus; + @Autowired + private TenantAware tenantAware; + @Autowired private AfterTransactionCommitExecutor afterCommit; @@ -206,6 +211,8 @@ public class JpaTargetManagement implements TargetManagement { targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); targetRepository.deleteByIdIn(targetsForCurrentTenant); } + targetsForCurrentTenant + .forEach(targetId -> eventBus.post(new TargetDeletedEvent(tenantAware.getCurrentTenant(), targetId))); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java deleted file mode 100644 index 5f41063d2..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository.jpa.eventbus; - -import java.util.Collection; - -import javax.persistence.EntityManager; - -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; -import org.eclipse.hawkbit.repository.jpa.TargetRepository; -import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.common.eventbus.EventBus; - -/** - * An aspect implementation which wraps the necessary repository services for - * saving {@link TenantAwareBaseEntity}s to publish create or update events. - * - * - * - * - */ -@Service -@Aspect -public class EntityChangeEventListener { - - @Autowired - private EventBus eventBus; - - @Autowired - private TenantAware tenantAware; - - @Autowired - private EntityManager entityManager; - - @Autowired - private AfterTransactionCommitExecutor afterCommit; - - /** - * In case the a {@link Target} is created a corresponding - * {@link TargetInfo} is created as well. We need the {@link TargetInfo} - * information in the target created event. So we are listening to the - * {@link TargetInfo} creation to indicate if an Target has been created. - * - * @param joinpoint - * the aspect join point - * @return the object of the {@link ProceedingJoinPoint#proceed()} - * @throws Throwable - * in case exception happens in the - * {@link ProceedingJoinPoint#proceed()} - */ - @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetInfoRepository.save(..))") - // Exception squid:S00112 - Is aspectJ proxy - @SuppressWarnings({ "squid:S00112" }) - public Object targetCreated(final ProceedingJoinPoint joinpoint) throws Throwable { - final boolean isNew = isTargetInfoNew(joinpoint.getArgs()[0]); - final Object result = joinpoint.proceed(); - if (result instanceof TargetInfo) { - if (isNew) { - notifyTargetCreated(entityManager.merge(entityManager.merge(((TargetInfo) result).getTarget()))); - } else { - notifyTargetInfoChanged((TargetInfo) result); - } - } - return result; - } - - /** - * Proxy method around the delete method of the {@link TargetRepository} to - * notify the {@link TargetDeletedEvent} in case targets has been deleted. - * - * @param joinpoint - * the aspect join point - * @return the object of the {@link ProceedingJoinPoint#proceed()} - * @throws Throwable - * in case exception happens in the - * {@link ProceedingJoinPoint#proceed()} - */ - @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetRepository.deleteByIdIn(..))") - // Exception squid:S00112 - Is aspectJ proxy - @SuppressWarnings({ "squid:S00112" }) - public Object targetDeletedById(final ProceedingJoinPoint joinpoint) throws Throwable { - final String currentTenant = tenantAware.getCurrentTenant(); - final Object result = joinpoint.proceed(); - final Collection targetIds = (Collection) joinpoint.getArgs()[0]; - targetIds.forEach(targetId -> notifyTargetDeleted(currentTenant, targetId)); - return result; - } - - /** - * Proxy method around the delete method of the {@link TargetRepository} to - * notify the {@link TargetDeletedEvent} in case targets has been deleted. - * - * @param joinpoint - * the aspect join point - * @return the object of the {@link ProceedingJoinPoint#proceed()} - * @throws Throwable - * in case exception happens in the - * {@link ProceedingJoinPoint#proceed()} - */ - @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetRepository.delete(..))") - // Exception squid:S00112 - Is aspectJ proxy - @SuppressWarnings({ "squid:S00112", "unchecked" }) - public Object targetDeleted(final ProceedingJoinPoint joinpoint) throws Throwable { - final String currentTenant = tenantAware.getCurrentTenant(); - final Object result = joinpoint.proceed(); - final Object param = joinpoint.getArgs()[0]; - // delete by id - if (param instanceof Long) { - notifyTargetDeleted(currentTenant, (Long) param); - } else if (param instanceof Target) { - notifyTargetDeleted(currentTenant, ((Target) param).getId()); - } else if (param instanceof Iterable) { - ((Iterable) param).forEach(target -> notifyTargetDeleted(currentTenant, target.getId())); - } - return result; - } - - private void notifyTargetCreated(final Target t) { - afterCommit.afterCommit(() -> eventBus.post(new TargetCreatedEvent(t))); - - } - - private void notifyTargetInfoChanged(final TargetInfo targetInfo) { - afterCommit.afterCommit(() -> eventBus.post(new TargetInfoUpdateEvent(targetInfo))); - } - - private void notifyTargetDeleted(final String tenant, final Long targetId) { - afterCommit.afterCommit(() -> eventBus.post(new TargetDeletedEvent(tenant, targetId))); - } - - private static boolean isTargetInfoNew(final Object targetInfo) { - return ((JpaTargetInfo) targetInfo).isNew(); - } - -} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java index ca8ac60df..ef1868c3f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java @@ -179,4 +179,5 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity { return true; } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java index 2dd0fdb40..27fbc687e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java @@ -8,79 +8,47 @@ */ package org.eclipse.hawkbit.repository.jpa.model; -import java.util.Map; -import java.util.stream.Collectors; - -import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent; -import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.DescriptorEventAdapter; -import org.eclipse.persistence.internal.sessions.ObjectChangeSet; -import org.eclipse.persistence.queries.UpdateObjectQuery; -import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord; - -import com.google.common.eventbus.EventBus; /** - * Listens to change in property values of an entity. + * Listens to change in property values of an entity and calls the corresponding + * {@link EventAwareEntity}. * */ public class EntityPropertyChangeListener extends DescriptorEventAdapter { @Override public void postInsert(final DescriptorEvent event) { - if (event.getObject().getClass().equals(Action.class)) { - final Action action = (Action) event.getObject(); - if (action.getRollout() != null) { - final EventBus eventBus = getEventBus(); - final AfterTransactionCommitExecutor afterCommit = getAfterTransactionCommmitExecutor(); - afterCommit.afterCommit(() -> eventBus.post(new ActionCreatedEvent(action))); - } + final Object object = event.getObject(); + if (isEventAwareEntity(object)) { + doNotifiy(() -> ((EventAwareEntity) object).fireCreateEvent(event)); } - } @Override public void postUpdate(final DescriptorEvent event) { - if (event.getObject().getClass().equals(JpaAction.class)) { - getAfterTransactionCommmitExecutor().afterCommit(() -> getEventBus().post( - new ActionPropertyChangeEvent((Action) event.getObject(), getChangeSet(Action.class, event)))); - } else if (event.getObject().getClass().equals(JpaRollout.class)) { - getAfterTransactionCommmitExecutor().afterCommit(() -> getEventBus().post( - new RolloutPropertyChangeEvent((Rollout) event.getObject(), getChangeSet(Rollout.class, event)))); - } else if (event.getObject().getClass().equals(JpaRolloutGroup.class)) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post(new RolloutGroupPropertyChangeEvent((RolloutGroup) event.getObject(), - getChangeSet(RolloutGroup.class, event)))); + final Object object = event.getObject(); + if (isEventAwareEntity(object)) { + doNotifiy(() -> ((EventAwareEntity) object).fireUpdateEvent(event)); } } - private Map.Values> getChangeSet( - final Class clazz, final DescriptorEvent event) { - final T rolloutGroup = clazz.cast(event.getObject()); - final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet(); - return changeSet.getChanges().stream().filter(record -> record instanceof DirectToFieldChangeRecord) - .map(record -> (DirectToFieldChangeRecord) record) - .collect(Collectors.toMap(record -> record.getAttribute(), - record -> new AbstractPropertyChangeEvent(rolloutGroup, null).new Values( - record.getOldValue(), record.getNewValue()))); + @Override + public void postDelete(final DescriptorEvent event) { + final Object object = event.getObject(); + if (isEventAwareEntity(object)) { + doNotifiy(() -> ((EventAwareEntity) object).fireDeleteEvent(event)); + } } - private AfterTransactionCommitExecutor getAfterTransactionCommmitExecutor() { - return AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit(); + private boolean isEventAwareEntity(final Object object) { + return object instanceof EventAwareEntity; } - private EventBus getEventBus() { - return EventBusHolder.getInstance().getEventBus(); + private void doNotifiy(final Runnable runnable) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(runnable); } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java new file mode 100644 index 000000000..889a61796 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.model; + +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * Interfaces which can be implemented by entities to be called when the entity + * should fire an event because the entity has been created, updated or deleted. + */ +public interface EventAwareEntity { + + /** + * Fired for the Entity creation. + * + * @param descriptorEvent + */ + void fireCreateEvent(DescriptorEvent descriptorEvent); + + /** + * Fired for the Entity updation. + * + * @param descriptorEvent + */ + void fireUpdateEvent(DescriptorEvent descriptorEvent); + + /** + * Fired for the Entity deletion. + * + * @param descriptorEvent + */ + void fireDeleteEvent(DescriptorEvent descriptorEvent); +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index 5fa2c3bed..72ef46ba3 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -28,6 +28,10 @@ import javax.persistence.NamedSubgraph; import javax.persistence.OneToMany; import javax.persistence.Table; +import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; @@ -35,6 +39,7 @@ import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; /** * JPA implementation of {@link Action}. @@ -49,7 +54,7 @@ import org.eclipse.persistence.annotations.CascadeOnDelete; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action { +public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action, EventAwareEntity { private static final long serialVersionUID = 1L; @ManyToOne(fetch = FetchType.LAZY) @@ -171,4 +176,20 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]"; } + @Override + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(this)); + } + + @Override + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new ActionPropertyChangeEvent(this, + EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent))); + } + + @Override + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no action deletion + } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java index 676215424..0fa2d0c33 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java @@ -13,6 +13,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -33,8 +34,14 @@ import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; +import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; @@ -45,6 +52,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; /** * Jpa implementation of {@link DistributionSet}. @@ -61,9 +69,13 @@ import org.eclipse.persistence.annotations.CascadeOnDelete; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet { +public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet, EventAwareEntity { private static final long serialVersionUID = 1L; + private static final String COMPLETE_PROPERTY = "complete"; + + private static final String DELETED_PROPERTY = "deleted"; + @Column(name = "required_migration_step") private boolean requiredMigrationStep; @@ -279,4 +291,30 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen return complete; } + @Override + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(this)); + } + + @Override + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + + final Map.Values> changeSet = EntityPropertyChangeHelper + .getChangeSet(JpaDistributionSet.class, descriptorEvent); + EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(this)); + + if (changeSet.containsKey(DELETED_PROPERTY)) { + final Boolean newDeleted = (Boolean) changeSet.get(DELETED_PROPERTY).getNewValue(); + if (newDeleted) { + EventBusHolder.getInstance().getEventBus().post(new DistributionDeletedEvent(getTenant(), getId())); + } + } + + } + + @Override + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new DistributionDeletedEvent(getTenant(), getId())); + } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java index 3cbe65717..85395e27b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java @@ -25,13 +25,17 @@ import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent; import org.eclipse.hawkbit.repository.jpa.cache.CacheField; import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys; +import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; +import org.eclipse.persistence.descriptors.DescriptorEvent; /** * JPA implementation of a {@link Rollout}. @@ -44,7 +48,7 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaRollout extends AbstractJpaNamedEntity implements Rollout { +public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, EventAwareEntity { private static final long serialVersionUID = 1L; @@ -197,4 +201,21 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout { + ", getName()=" + getName() + ", getId()=" + getId() + "]"; } + @Override + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + // there is no rollout creation event + } + + @Override + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new RolloutPropertyChangeEvent(this, + EntityPropertyChangeHelper.getChangeSet(Rollout.class, descriptorEvent))); + + } + + @Override + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no rollout deletion event + } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java index 79da6630a..9bb8644f4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java @@ -25,9 +25,13 @@ import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; +import org.eclipse.persistence.descriptors.DescriptorEvent; /** * JPA entity definition of persisting a group of an rollout. @@ -40,7 +44,7 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup { +public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup, EventAwareEntity { private static final long serialVersionUID = 1L; @@ -236,4 +240,19 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr + ", getId()=" + getId() + "]"; } + @Override + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + // there is no RolloutGroup created event + } + + @Override + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new RolloutGroupPropertyChangeEvent(this, + EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent))); + } + + @Override + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no RolloutGroup deleted event + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index 183405470..c91247321 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -36,6 +36,10 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityChecker; import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; @@ -45,6 +49,7 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; import org.springframework.data.domain.Persistable; /** @@ -64,7 +69,7 @@ import org.springframework.data.domain.Persistable; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target { +public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target, EventAwareEntity { private static final long serialVersionUID = 1L; @Column(name = "controller_id", length = 64) @@ -222,6 +227,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, TargetInfo { +@EntityListeners(EntityPropertyChangeListener.class) +public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareEntity { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class); @@ -321,4 +326,19 @@ public class JpaTargetInfo implements Persistable, TargetInfo { } return true; } + + @Override + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + // there is no target info created event + } + + @Override + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(this)); + } + + @Override + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no target info deleted event + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java new file mode 100644 index 000000000..2be398e24 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.model.helper; + +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; +import org.eclipse.persistence.descriptors.DescriptorEvent; +import org.eclipse.persistence.internal.sessions.ObjectChangeSet; +import org.eclipse.persistence.queries.UpdateObjectQuery; +import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord; + +/** + * Helper class to get the change set for the property changes in the Entity. + * + * @param + */ +public class EntityPropertyChangeHelper { + + /** + * To get the map of entity property change set + * + * @param clazz + * @param event + * @return the map of the changeSet + */ + public static Map.Values> getChangeSet( + final Class clazz, final DescriptorEvent event) { + final T rolloutGroup = clazz.cast(event.getObject()); + final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet(); + return changeSet.getChanges().stream().filter(record -> record instanceof DirectToFieldChangeRecord) + .map(record -> (DirectToFieldChangeRecord) record) + .collect(Collectors.toMap(record -> record.getAttribute(), + record -> new AbstractPropertyChangeEvent(rolloutGroup, null).new Values( + record.getOldValue(), record.getNewValue()))); + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/RepositoryEntityEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/RepositoryEntityEventTest.java new file mode 100644 index 000000000..0aa305d52 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/RepositoryEntityEventTest.java @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.eventbus; + +import static org.fest.assertions.Assertions.assertThat; + +import java.net.URI; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.eventbus.event.Event; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.fest.assertions.api.Assertions; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +import ru.yandex.qatools.allure.annotations.Description; +import ru.yandex.qatools.allure.annotations.Features; +import ru.yandex.qatools.allure.annotations.Stories; + +@Features("Component Tests - Repository") +@Stories("Entity Events") +public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest { + + @Autowired + private EventBus eventBus; + + private final MyEventListener eventListener = new MyEventListener(); + + @Before + public void beforeTest() { + eventListener.queue.clear(); + eventBus.register(eventListener); + } + + @Test + @Description("Verifies that the target created event is published when a target has been created") + public void targetCreatedEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + + final TargetCreatedEvent targetCreatedEvent = eventListener.waitForEvent(TargetCreatedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetCreatedEvent).isNotNull(); + assertThat(targetCreatedEvent.getEntity().getId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the target update event is published when a target has been updated") + public void targetUpdateEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + createdTarget.setName("updateName"); + targetManagement.updateTarget(createdTarget); + + final TargetUpdatedEvent targetUpdatedEvent = eventListener.waitForEvent(TargetUpdatedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetUpdatedEvent).isNotNull(); + assertThat(targetUpdatedEvent.getEntity().getId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the target info update event is published when a target info has been updated") + public void targetInfoUpdateEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + controllerManagament.updateTargetStatus(createdTarget.getTargetInfo(), TargetUpdateStatus.PENDING, + System.currentTimeMillis(), URI.create("http://127.0.0.1")); + + final TargetInfoUpdateEvent targetInfoUpdatedEvent = eventListener.waitForEvent(TargetInfoUpdateEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetInfoUpdatedEvent).isNotNull(); + assertThat(targetInfoUpdatedEvent.getEntity().getTarget().getId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the target deleted event is published when a target has been deleted") + public void targetDeletedEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + + targetManagement.deleteTargets(createdTarget.getId()); + + final TargetDeletedEvent targetDeletedEvent = eventListener.waitForEvent(TargetDeletedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetDeletedEvent).isNotNull(); + assertThat(targetDeletedEvent.getTargetId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the distribution set created event is published when a distribution set has been created") + public void distributionSetCreatedEventIsPublished() throws InterruptedException { + final DistributionSet generateDistributionSet = entityFactory.generateDistributionSet(); + generateDistributionSet.setName("dsEventTest"); + generateDistributionSet.setVersion("1"); + final DistributionSet createDistributionSet = distributionSetManagement + .createDistributionSet(generateDistributionSet); + + final DistributionCreatedEvent dsCreatedEvent = eventListener.waitForEvent(DistributionCreatedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(dsCreatedEvent).isNotNull(); + assertThat(dsCreatedEvent.getEntity().getId()).isEqualTo(createDistributionSet.getId()); + } + + @Test + @Description("Verifies that the distribution set deleted event is published when a distribution set has been deleted") + public void distributionSetDeletedEventIsPublished() throws InterruptedException { + + final DistributionSet generateDistributionSet = entityFactory.generateDistributionSet(); + generateDistributionSet.setName("dsEventTest"); + generateDistributionSet.setVersion("1"); + final DistributionSet createDistributionSet = distributionSetManagement + .createDistributionSet(generateDistributionSet); + + distributionSetManagement.deleteDistributionSet(createDistributionSet); + + final DistributionDeletedEvent dsDeletedEvent = eventListener.waitForEvent(DistributionDeletedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(dsDeletedEvent).isNotNull(); + assertThat(dsDeletedEvent.getDistributionSetId()).isEqualTo(createDistributionSet.getId()); + } + + private class MyEventListener { + + private final BlockingQueue queue = new LinkedBlockingQueue<>(); + + @Subscribe + public void onEvent(final Event event) { + queue.offer(event); + } + + public T waitForEvent(final Class eventType, final long timeout, final TimeUnit timeUnit) + throws InterruptedException { + Event event = null; + while ((event = queue.poll(timeout, timeUnit)) != null) { + if (event.getClass().isAssignableFrom(eventType)) { + return (T) event; + } + } + Assertions.fail("Missing event " + eventType + " within timeout " + timeout + " " + timeUnit); + return null; + } + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java index cca4bdd4c..f064a76a1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java @@ -12,25 +12,29 @@ import java.util.HashSet; import java.util.Set; import org.eclipse.hawkbit.eventbus.event.Event; -import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagCreatedBulkEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; import org.eclipse.hawkbit.repository.eventbus.event.RolloutChangeEvent; import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupChangeEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetTagCreatedBulkEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetTagDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetTagUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; /** * The default hawkbit event provider. */ public class HawkbitEventProvider implements UIEventProvider { - private static final Set> SINGLE_EVENTS = new HashSet<>(6); - private static final Set> BULK_EVENTS = new HashSet<>(3); + private static final Set> SINGLE_EVENTS = new HashSet<>(9); + private static final Set> BULK_EVENTS = new HashSet<>(5); static { SINGLE_EVENTS.add(TargetTagCreatedBulkEvent.class); @@ -41,10 +45,14 @@ public class HawkbitEventProvider implements UIEventProvider { SINGLE_EVENTS.add(RolloutGroupChangeEvent.class); SINGLE_EVENTS.add(RolloutChangeEvent.class); SINGLE_EVENTS.add(TargetTagUpdateEvent.class); + SINGLE_EVENTS.add(DistributionSetUpdateEvent.class); BULK_EVENTS.add(TargetCreatedEvent.class); BULK_EVENTS.add(TargetInfoUpdateEvent.class); BULK_EVENTS.add(TargetDeletedEvent.class); + BULK_EVENTS.add(DistributionDeletedEvent.class); + BULK_EVENTS.add(DistributionCreatedEvent.class); + BULK_EVENTS.add(TargetUpdatedEvent.class); } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java index b0b563f0e..df6483592 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java @@ -222,7 +222,6 @@ public abstract class AbstractTableDetailsLayout extends populateLog(); populateDescription(); populateDetailsWidget(); - populateMetadataDetails(); } protected void populateLog() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java index d3892a9dc..6a2c0401f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java @@ -40,38 +40,37 @@ import com.vaadin.ui.themes.ValoTheme; @SpringComponent @VaadinSessionScope -public class DistributionSetMetadatadetailslayout extends Table{ - +public class DistributionSetMetadatadetailslayout extends Table { + private static final long serialVersionUID = 2913758299611837718L; - - - private DistributionSetManagement distributionSetManagement; - + + private DistributionSetManagement distributionSetManagement; + private DsMetadataPopupLayout dsMetadataPopupLayout; private static final String METADATA_KEY = "Key"; - - private static final String VIEW ="view"; + + private static final String VIEW = "view"; private SpPermissionChecker permissionChecker; - + private transient EntityFactory entityFactory; private I18N i18n; - - private Long selectedDistSetId; - - /** - * - * @param i18n - * @param permissionChecker - * @param distributionSetManagement - * @param dsMetadataPopupLayout - */ + + private Long selectedDistSetId; + + /** + * Initialize the component. + * @param i18n + * @param permissionChecker + * @param distributionSetManagement + * @param dsMetadataPopupLayout + * @param entityFactory + */ public void init(final I18N i18n, final SpPermissionChecker permissionChecker, - final DistributionSetManagement distributionSetManagement, - final DsMetadataPopupLayout dsMetadataPopupLayout, - final EntityFactory entityFactory) { + final DistributionSetManagement distributionSetManagement, + final DsMetadataPopupLayout dsMetadataPopupLayout, final EntityFactory entityFactory) { this.i18n = i18n; this.permissionChecker = permissionChecker; this.distributionSetManagement = distributionSetManagement; @@ -80,7 +79,6 @@ public class DistributionSetMetadatadetailslayout extends Table{ createDSMetadataTable(); addCustomGeneratedColumns(); } - /** * Populate software module metadata. @@ -90,35 +88,15 @@ public class DistributionSetMetadatadetailslayout extends Table{ public void populateDSMetadata(final DistributionSet distributionSet) { removeAllItems(); if (null == distributionSet) { - return; + return; } selectedDistSetId = distributionSet.getId(); - final List dsMetadataList = distributionSet.getMetadata(); + final List dsMetadataList = distributionSetManagement + .findDistributionSetMetadataByDistributionSetId(selectedDistSetId); if (null != dsMetadataList && !dsMetadataList.isEmpty()) { dsMetadataList.forEach(dsMetadata -> setDSMetadataProperties(dsMetadata)); } - - } - - /** - * Create metadata . - * - * @param metadataKeyName - */ - public void createMetadata(final String metadataKeyName){ - final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); - final Item item = metadataContainer.addItem(metadataKeyName); - item.getItemProperty(METADATA_KEY).setValue(metadataKeyName); - } - - /** - * Delete metadata. - * - * @param metadataKeyName - */ - public void deleteMetadata(final String metadataKeyName){ - final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); - metadataContainer.removeItem(metadataKeyName); + } private void createDSMetadataTable() { @@ -131,9 +109,9 @@ public class DistributionSetMetadatadetailslayout extends Table{ setContainerDataSource(getDistSetContainer()); setColumnHeaderMode(ColumnHeaderMode.EXPLICIT); addDSMetadataTableHeader(); - setSizeFull(); - //same as height of other tabs in details tabsheet - setHeight(116,Unit.PIXELS); + setSizeFull(); + // same as height of other tabs in details tabsheet + setHeight(116, Unit.PIXELS); } private IndexedContainer getDistSetContainer() { @@ -141,7 +119,7 @@ public class DistributionSetMetadatadetailslayout extends Table{ container.addContainerProperty(METADATA_KEY, String.class, ""); setColumnExpandRatio(METADATA_KEY, 0.7f); setColumnAlignment(METADATA_KEY, Align.LEFT); - + if (permissionChecker.hasUpdateDistributionPermission()) { container.addContainerProperty(VIEW, Label.class, ""); setColumnExpandRatio(VIEW, 0.2F); @@ -154,39 +132,36 @@ public class DistributionSetMetadatadetailslayout extends Table{ setColumnHeader(METADATA_KEY, i18n.get("header.key")); } - - private void setDSMetadataProperties(final DistributionSetMetadata dsMetadata){ + private void setDSMetadataProperties(final DistributionSetMetadata dsMetadata) { final Item item = getContainerDataSource().addItem(dsMetadata.getKey()); item.getItemProperty(METADATA_KEY).setValue(dsMetadata.getKey()); - + } - - private void addCustomGeneratedColumns() { - addGeneratedColumn(METADATA_KEY, - (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); + + private void addCustomGeneratedColumns() { + addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); } private Button customMetadataDetailButton(final String metadataKey) { - final Button viewIcon = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, "View " - + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); + final Button viewIcon = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, + "View " + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); viewIcon.setData(metadataKey); viewIcon.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link" + " " + "text-style"); viewIcon.addClickListener(event -> showMetadataDetails(selectedDistSetId, metadataKey)); return viewIcon; } - + private static String getDetailLinkId(final String name) { - return new StringBuilder(SPUIComponentIdProvider.DS_METADATA_DETAIL_LINK).append('.').append(name) - .toString(); + return new StringBuilder(SPUIComponentIdProvider.DS_METADATA_DETAIL_LINK).append('.').append(name).toString(); } - - private void showMetadataDetails(final Long selectedDistSetId , final String metadataKey) { - DistributionSet distSet = distributionSetManagement.findDistributionSetById(selectedDistSetId); - + + private void showMetadataDetails(final Long selectedDistSetId, final String metadataKey) { + final DistributionSet distSet = distributionSetManagement.findDistributionSetById(selectedDistSetId); + /* display the window */ UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(distSet, - entityFactory.generateDistributionSetMetadata(distSet, metadataKey, "") )); + entityFactory.generateDistributionSetMetadata(distSet, metadataKey, ""))); } - + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java index d5753c033..fd5c1d59f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java @@ -41,19 +41,19 @@ import com.vaadin.ui.themes.ValoTheme; @ViewScope public class SoftwareModuleMetadatadetailslayout extends Table { - private static final long serialVersionUID = 2913758299611838818L; + private static final long serialVersionUID = 2913758299611838818L; - private static final String METADATA_KEY = "Key"; + private static final String METADATA_KEY = "Key"; - private SpPermissionChecker permissionChecker; + private SpPermissionChecker permissionChecker; private transient SoftwareManagement softwareManagement; - private SwMetadataPopupLayout swMetadataPopupLayout; + private SwMetadataPopupLayout swMetadataPopupLayout; - private I18N i18n; + private I18N i18n; - private Long selectedSWModuleId; + private Long selectedSWModuleId; private transient EntityFactory entityFactory; @@ -83,100 +83,102 @@ public class SoftwareModuleMetadatadetailslayout extends Table { addCustomGeneratedColumns(); } - /** - * Populate software module metadata table. - * - * @param swModule - */ - public void populateSMMetadata(final SoftwareModule swModule) { - removeAllItems(); - if (null == swModule) { - return; - } - selectedSWModuleId = swModule.getId(); - final List swMetadataList = swModule.getMetadata(); - if (null != swMetadataList && !swMetadataList.isEmpty()) { - swMetadataList.forEach(swMetadata -> setSWMetadataProperties(swMetadata)); - } - } + /** + * Populate software module metadata table. + * + * @param swModule + */ + public void populateSMMetadata(final SoftwareModule swModule) { + removeAllItems(); + if (null == swModule) { + return; + } + selectedSWModuleId = swModule.getId(); + final List swMetadataList = softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(selectedSWModuleId); + if (null != swMetadataList && !swMetadataList.isEmpty()) { + swMetadataList.forEach(swMetadata -> setSWMetadataProperties(swMetadata)); + } + } - /** - * Create metadata. - * - * @param metadataKeyName - */ - public void createMetadata(final String metadataKeyName) { - final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); - final Item item = metadataContainer.addItem(metadataKeyName); - item.getItemProperty(METADATA_KEY).setValue(metadataKeyName); + /** + * Create metadata. + * + * @param metadataKeyName + */ + public void createMetadata(final String metadataKeyName) { + final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); + final Item item = metadataContainer.addItem(metadataKeyName); + item.getItemProperty(METADATA_KEY).setValue(metadataKeyName); - } + } - /** - * Delete metadata. - * - * @param metadataKeyName - */ - public void deleteMetadata(final String metadataKeyName) { - final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); - metadataContainer.removeItem(metadataKeyName); - } + /** + * Delete metadata. + * + * @param metadataKeyName + */ + public void deleteMetadata(final String metadataKeyName) { + final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); + metadataContainer.removeItem(metadataKeyName); + } - private void createSWMMetadataTable() { - addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES); - addStyleName(ValoTheme.TABLE_NO_STRIPES); - addStyleName(SPUIStyleDefinitions.SW_MODULE_TABLE); - setSelectable(false); - setImmediate(true); - setContainerDataSource(getSwModuleMetadataContainer()); - setColumnHeaderMode(ColumnHeaderMode.EXPLICIT); - addSMMetadataTableHeader(); - setSizeFull(); - // same as height of other tabs in details tabsheet - setHeight(116, Unit.PIXELS); - } + private void createSWMMetadataTable() { + addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES); + addStyleName(ValoTheme.TABLE_NO_STRIPES); + addStyleName(SPUIStyleDefinitions.SW_MODULE_TABLE); + setSelectable(false); + setImmediate(true); + setContainerDataSource(getSwModuleMetadataContainer()); + setColumnHeaderMode(ColumnHeaderMode.EXPLICIT); + addSMMetadataTableHeader(); + setSizeFull(); + //same as height of other tabs in details tabsheet + setHeight(116,Unit.PIXELS); + } - private IndexedContainer getSwModuleMetadataContainer() { - final IndexedContainer container = new IndexedContainer(); - container.addContainerProperty(METADATA_KEY, String.class, ""); - setColumnAlignment(METADATA_KEY, Align.LEFT); - return container; - } + private IndexedContainer getSwModuleMetadataContainer() { + final IndexedContainer container = new IndexedContainer(); + container.addContainerProperty(METADATA_KEY, String.class, ""); + setColumnAlignment(METADATA_KEY, Align.LEFT); + return container; + } - private void addSMMetadataTableHeader() { - setColumnHeader(METADATA_KEY, i18n.get("header.key")); - } + private void addSMMetadataTableHeader() { + setColumnHeader(METADATA_KEY, i18n.get("header.key")); + } - private void setSWMetadataProperties(final SoftwareModuleMetadata swMetadata) { - final Item item = getContainerDataSource().addItem(swMetadata.getKey()); - item.getItemProperty(METADATA_KEY).setValue(swMetadata.getKey()); - } - private void addCustomGeneratedColumns() { - addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); - } + private void setSWMetadataProperties(final SoftwareModuleMetadata swMetadata) { + final Item item = getContainerDataSource().addItem(swMetadata.getKey()); + item.getItemProperty(METADATA_KEY).setValue(swMetadata.getKey()); + } - private Button customMetadataDetailButton(final String metadataKey) { - final Button viewLink = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, - "View" + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); - viewLink.setData(metadataKey); - if (permissionChecker.hasUpdateDistributionPermission()) { - viewLink.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link" - + " " + "text-style"); - viewLink.addClickListener(event -> showMetadataDetails(selectedSWModuleId, metadataKey)); - } - return viewLink; - } + private void addCustomGeneratedColumns() { + addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); + } - private static String getDetailLinkId(final String name) { - return new StringBuilder(SPUIComponentIdProvider.SW_METADATA_DETAIL_LINK).append('.').append(name).toString(); - } + private Button customMetadataDetailButton(final String metadataKey) { + final Button viewLink = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, "View" + + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); + viewLink.setData(metadataKey); + if (permissionChecker.hasUpdateDistributionPermission()) { + viewLink.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link" + + " " + "text-style"); + viewLink.addClickListener(event -> showMetadataDetails(selectedSWModuleId, metadataKey)); + } + return viewLink; + } - private void showMetadataDetails(final Long selectedSWModuleId, final String metadataKey) { - final SoftwareModule swmodule = softwareManagement.findSoftwareModuleById(selectedSWModuleId); - /* display the window */ - UI.getCurrent().addWindow(swMetadataPopupLayout.getWindow(swmodule, - entityFactory.generateSoftwareModuleMetadata(swmodule, metadataKey, ""))); - } + private static String getDetailLinkId(final String name) { + return new StringBuilder(SPUIComponentIdProvider.SW_METADATA_DETAIL_LINK).append('.').append(name).toString(); + } + + private void showMetadataDetails(final Long selectedSWModuleId, final String metadataKey) { + final SoftwareModule swmodule = softwareManagement.findSoftwareModuleById(selectedSWModuleId); + /* display the window */ + UI.getCurrent().addWindow( + swMetadataPopupLayout.getWindow(swmodule, + entityFactory.generateSoftwareModuleMetadata(swmodule, metadataKey, ""))); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java index 5803f312b..06b23c51b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java @@ -17,7 +17,6 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleIdName; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent; @@ -29,7 +28,6 @@ import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsTable; import org.eclipse.hawkbit.ui.common.tagdetails.DistributionTagToken; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; import org.eclipse.hawkbit.ui.distributions.event.SaveActionWindowEvent; import org.eclipse.hawkbit.ui.distributions.event.SoftwareModuleAssignmentDiscardEvent; import org.eclipse.hawkbit.ui.distributions.state.ManageDistUIState; @@ -97,21 +95,6 @@ public class DistributionSetDetails extends AbstractNamedVersionedEntityTableDet private final Map assignedSWModule = new HashMap<>(); - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final MetadataEvent event) { - UI.getCurrent().access(() -> { - final DistributionSetMetadata dsMetadata = event.getDistributionSetMetadata(); - if (dsMetadata != null && isDistributionSetSelected(dsMetadata.getDistributionSet())) { - if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.CREATE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.createMetadata(event.getDistributionSetMetadata().getKey()); - } else if (event - .getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.DELETE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.deleteMetadata(event.getDistributionSetMetadata().getKey()); - } - } - }); - } - /** * softwareLayout Initialize the component. */ diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java index fc415f4de..6cda2cd16 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java @@ -21,6 +21,9 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleIdName; @@ -105,7 +108,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable visibleItemIds = (List) getVisibleItemIds(); + + // refresh the details tabs only if selected ds is updated + if (lastSelectedDsIdName != null && lastSelectedDsIdName.getId().equals(ds.getId())) { + // update table row+details layout + eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.SELECTED_ENTITY, ds)); + } else if (visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst().isPresent()) { + // update the name/version details visible in table + UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); + } + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvents(final List events) { + final Object firstEvent = events.get(0); + if (DistributionCreatedEvent.class.isInstance(firstEvent)) { + refreshDistributions(); + } else if (DistributionDeletedEvent.class.isInstance(firstEvent)) { + onDistributionDeleteEvent((List) events); + } + } + @Override protected String getTableId() { return SPUIComponentIdProvider.DIST_TABLE_ID; @@ -189,10 +219,10 @@ public class DistributionSetTable extends AbstractNamedVersionTable updateDistributionInTable(event.getEntity())); } @EventBusListenerMethod(scope = EventScope.SESSION) @@ -477,8 +511,9 @@ public class DistributionSetTable extends AbstractNamedVersionTable showMetadataDetails(((DistributionSetIdName) itemId).getId())); + manageMetaDataBtn + .addClickListener(event -> showMetadataDetails(((DistributionSetIdName) itemId).getId())); return manageMetaDataBtn; } }); } - @Override protected List getTableVisibleColumns() { @@ -513,7 +548,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable events) { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final List visibleItemIds = (List) getVisibleItemIds(); + boolean shouldRefreshDs = false; + for (final DistributionDeletedEvent deletedEvent : events) { + final Long distributionSetId = deletedEvent.getDistributionSetId(); + final DistributionSetIdName targetIdName = new DistributionSetIdName(distributionSetId, null, null); + if (visibleItemIds.contains(targetIdName)) { + dsContainer.removeItem(targetIdName); + } else { + shouldRefreshDs = true; + } + } + + if (shouldRefreshDs) { + refreshOnDelete(); + } else { + dsContainer.commit(); + } + reSelectItemsAfterDeletionEvent(); + } + + private void refreshOnDelete() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final int size = dsContainer.size(); + refreshTablecontainer(); + if (size != 0) { + setData(SPUIDefinitions.DATA_AVAILABLE); + } + } + + private void reSelectItemsAfterDeletionEvent() { + Set values = new HashSet<>(); + if (isMultiSelect()) { + values = new HashSet<>((Set) getValue()); + } else { + values.add(getValue()); + } + setValue(null); + + for (final Object value : values) { + if (getVisibleItemIds().contains(value)) { + select(value); + } + } + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java index 26eecab8f..8b035de45 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java @@ -16,8 +16,6 @@ import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.ui.common.AbstractMetadataPopupLayout; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent.MetadataUIEvent; import org.springframework.beans.factory.annotation.Autowired; import com.vaadin.spring.annotation.SpringComponent; @@ -55,7 +53,6 @@ public class DsMetadataPopupLayout extends AbstractMetadataPopupLayout { private static final long serialVersionUID = 5176481314404662215L; - private Sort sort = new Sort(Direction.ASC, "name", "version"); + private Sort sort = new Sort(Direction.ASC, "createdAt"); private String searchText = null; private transient DistributionSetManagement distributionSetManagement; private transient Page firstPageDistributionSets = null; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java index f82bc5c01..2436de9e5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.ui.distributions.event; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; + /** * * Metadata Events. @@ -18,21 +19,21 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; public class MetadataEvent { public enum MetadataUIEvent { - CREATE_DISTRIBUTION_SET_METADATA, DELETE_DISTRIBUTION_SET_METADATA, DELETE_SOFTWARE_MODULE_METADATA, CREATE_SOFTWARE_MODULE_METADATA; + DELETE_SOFTWARE_MODULE_METADATA, CREATE_SOFTWARE_MODULE_METADATA; } - private MetadataUIEvent metadataUIEvent; + private final MetadataUIEvent metadataUIEvent; private DistributionSetMetadata distributionSetMetadata; private SoftwareModuleMetadata softwareModuleMetadata; - public MetadataEvent(MetadataUIEvent metadataUIEvent, final DistributionSetMetadata distributionSetMetadata) { + public MetadataEvent(final MetadataUIEvent metadataUIEvent, final DistributionSetMetadata distributionSetMetadata) { this.metadataUIEvent = metadataUIEvent; this.distributionSetMetadata = distributionSetMetadata; } - public MetadataEvent(MetadataUIEvent metadataUIEvent, final SoftwareModuleMetadata softwareModuleMetadata) { + public MetadataEvent(final MetadataUIEvent metadataUIEvent, final SoftwareModuleMetadata softwareModuleMetadata) { this.metadataUIEvent = metadataUIEvent; this.softwareModuleMetadata = softwareModuleMetadata; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java index 35f88f5a1..80c9b0497 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java @@ -155,9 +155,9 @@ public class CustomTargetBeanQuery extends AbstractBeanQuery { size = getTargetManagement().countTargetByTargetFilterQuery(filterQuery); } getFilterManagementUIState().setTargetsCountAll(size); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - getFilterManagementUIState().setTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); - size = SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES; + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + getFilterManagementUIState().setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); + size = SPUIDefinitions.MAX_TABLE_ENTRIES; } else { getFilterManagementUIState().setTargetsTruncated(null); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java index 4700b48eb..c82467425 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java @@ -93,7 +93,7 @@ public class TargetFilterCountMessageLabel extends Label { // set the icon setIcon(FontAwesome.INFO_CIRCLE); setDescription(i18n.get("label.target.filter.truncated", filterManagementUIState.getTargetsTruncated(), - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES)); + SPUIDefinitions.MAX_TABLE_ENTRIES)); } else { setIcon(null); @@ -102,8 +102,8 @@ public class TargetFilterCountMessageLabel extends Label { targetMessage.append(totalTargets); targetMessage.append(HawkbitCommonUtil.SP_STRING_SPACE); targetMessage.append(i18n.get("label.filter.shown")); - if (totalTargets > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - targetMessage.append(SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + if (totalTargets > SPUIDefinitions.MAX_TABLE_ENTRIES) { + targetMessage.append(SPUIDefinitions.MAX_TABLE_ENTRIES); } else { targetMessage.append(HawkbitCommonUtil.SP_STRING_SPACE); targetMessage.append(totalTargets); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java index a10176235..76690dd72 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java @@ -9,7 +9,9 @@ package org.eclipse.hawkbit.ui.management.dstable; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import javax.annotation.PostConstruct; @@ -21,10 +23,12 @@ import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.TenantMetaData; import org.eclipse.hawkbit.ui.common.CommonDialogWindow; +import org.eclipse.hawkbit.ui.common.DistributionSetIdName; import org.eclipse.hawkbit.ui.common.DistributionSetTypeBeanQuery; import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIWindowDecorator; +import org.eclipse.hawkbit.ui.distributions.dstable.DistributionSetTable; import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent; import org.eclipse.hawkbit.ui.management.event.DragEvent; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; @@ -33,6 +37,7 @@ import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; +import org.eclipse.hawkbit.ui.utils.SpringContextHelper; import org.eclipse.hawkbit.ui.utils.UINotification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -237,7 +242,10 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent { notificationMessage.displaySuccess( i18n.get("message.new.dist.save.success", new Object[] { newDist.getName(), newDist.getVersion() })); - eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.NEW_ENTITY, newDist)); + final Set s = new HashSet<>(); + s.add(new DistributionSetIdName(newDist.getId(), newDist.getName(), newDist.getVersion())); + final DistributionSetTable distributionSetTable = SpringContextHelper.getBean(DistributionSetTable.class); + distributionSetTable.setValue(s); } /** diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java index 63ed91250..672cc0a1c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java @@ -41,7 +41,7 @@ import com.google.common.base.Strings; public class DistributionBeanQuery extends AbstractBeanQuery { private static final long serialVersionUID = 5862679853949173536L; - private Sort sort = new Sort(Direction.ASC, "name", "version"); + private Sort sort = new Sort(Direction.ASC, "createdAt"); private Collection distributionTags; private String searchText; private String pinnedControllerId; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java index c3b19fb4b..9992b09e2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java @@ -11,7 +11,6 @@ package org.eclipse.hawkbit.ui.management.dstable; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.ui.common.DistributionSetIdName; import org.eclipse.hawkbit.ui.common.detailslayout.AbstractNamedVersionedEntityTableDetailsLayout; import org.eclipse.hawkbit.ui.common.detailslayout.DistributionSetMetadatadetailslayout; @@ -19,7 +18,6 @@ import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsTable; import org.eclipse.hawkbit.ui.common.tagdetails.DistributionTagToken; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.distributions.dstable.DsMetadataPopupLayout; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent; import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; @@ -79,21 +77,6 @@ public class DistributionDetails extends AbstractNamedVersionedEntityTableDetail super.init(); } - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final MetadataEvent event) { - UI.getCurrent().access(() -> { - final DistributionSetMetadata dsMetadata = event.getDistributionSetMetadata(); - if (dsMetadata != null && isDistributionSetSelected(dsMetadata.getDistributionSet())) { - if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.CREATE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.createMetadata(event.getDistributionSetMetadata().getKey()); - } else if (event - .getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.DELETE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.deleteMetadata(event.getDistributionSetMetadata().getKey()); - } - } - }); - } - @EventBusListenerMethod(scope = EventScope.SESSION) void onEvent(final DistributionTableEvent distributionTableEvent) { onBaseEntityEvent(distributionTableEvent); @@ -210,18 +193,18 @@ public class DistributionDetails extends AbstractNamedVersionedEntityTableDetail return true; } - private boolean isDistributionSetSelected(final DistributionSet ds) { - final DistributionSetIdName lastselectedManageDS = managementUIState.getLastSelectedDistribution().isPresent() ? managementUIState - .getLastSelectedDistribution().get() : null; - return ds!=null && lastselectedManageDS != null && lastselectedManageDS.getName().equals(ds.getName()) + final DistributionSetIdName lastselectedManageDS = managementUIState.getLastSelectedDistribution().isPresent() + ? managementUIState.getLastSelectedDistribution().get() : null; + return ds != null && lastselectedManageDS != null && lastselectedManageDS.getName().equals(ds.getName()) && lastselectedManageDS.getVersion().endsWith(ds.getVersion()); } @Override protected void showMetadata(final ClickEvent event) { - final DistributionSet ds = distributionSetManagement.findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); - UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds,null)); + final DistributionSet ds = distributionSetManagement + .findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); + UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds, null)); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java index ed69ee9a2..e4313dd80 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java @@ -18,8 +18,12 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.Target; @@ -99,6 +103,9 @@ public class DistributionTable extends AbstractNamedVersionTable events) { + final Object firstEvent = events.get(0); + if (DistributionDeletedEvent.class.isInstance(firstEvent)) { + onDistributionDeleteEvent((List) events); + } else if (DistributionCreatedEvent.class.isInstance(firstEvent) + && ((DistributionCreatedEvent) firstEvent).getEntity().isComplete()) { + refreshDistributions(); + } + + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvents(final DistributionSetUpdateEvent event) { + final DistributionSet ds = event.getEntity(); + + final List visibleItemIds = (List) getVisibleItemIds(); + + final Boolean dsVisible = visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst() + .isPresent(); + + if ((ds.isComplete() && !dsVisible)) { + refreshDistributions(); + } else if ((!ds.isComplete() && dsVisible)) { + refreshDistributions(); + if (ds.getId().equals(managementUIState.getLastSelectedDsIdName().getId())) { + managementUIState.setLastSelectedDistribution(null); + managementUIState.setLastSelectedEntity(null); + } + + } else if (dsVisible) { + UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); + } + final DistributionSetIdName lastSelectedDsIdName = managementUIState.getLastSelectedDsIdName(); + // refresh the details tabs only if selected ds is updated + if (lastSelectedDsIdName != null && lastSelectedDsIdName.getId().equals(ds.getId())) { + // update table row+details layout + eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.SELECTED_ENTITY, ds)); + } + } + /** * DistributionTableFilterEvent. * @@ -699,4 +747,67 @@ public class DistributionTable extends AbstractNamedVersionTable events) { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final List visibleItemIds = (List) getVisibleItemIds(); + boolean shouldRefreshDs = false; + for (final DistributionDeletedEvent deletedEvent : events) { + final Long distributionSetId = deletedEvent.getDistributionSetId(); + final DistributionSetIdName targetIdName = new DistributionSetIdName(distributionSetId, null, null); + if (visibleItemIds.contains(targetIdName)) { + dsContainer.removeItem(targetIdName); + } else { + shouldRefreshDs = true; + } + } + + if (shouldRefreshDs) { + refreshOnDelete(); + } else { + dsContainer.commit(); + } + reSelectItemsAfterDeletionEvent(); + } + + private void reSelectItemsAfterDeletionEvent() { + Set values = new HashSet<>(); + if (isMultiSelect()) { + values = new HashSet<>((Set) getValue()); + } else { + values.add(getValue()); + } + setValue(null); + + for (final Object value : values) { + if (getVisibleItemIds().contains(value)) { + select(value); + } + } + } + + private void refreshDistributions() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final int size = dsContainer.size(); + if (size < SPUIDefinitions.MAX_TABLE_ENTRIES) { + refreshTablecontainer(); + } + if (size != 0) { + setData(SPUIDefinitions.DATA_AVAILABLE); + } + } + + private void refreshOnDelete() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final int size = dsContainer.size(); + refreshTablecontainer(); + if (size != 0) { + setData(SPUIDefinitions.DATA_AVAILABLE); + } + } + + private void refreshTablecontainer() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + dsContainer.refresh(); + selectRow(); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java index fccee7cb5..6cf01410d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java @@ -174,7 +174,7 @@ public class CountMessageLabel extends Label { // set the icon setIcon(FontAwesome.INFO_CIRCLE); setDescription(i18n.get("label.target.filter.truncated", managementUIState.getTargetsTruncated(), - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES)); + SPUIDefinitions.MAX_TABLE_ENTRIES)); totalTargetTableEnteries += managementUIState.getTargetsTruncated(); } else { setIcon(null); @@ -184,9 +184,9 @@ public class CountMessageLabel extends Label { final StringBuilder message = new StringBuilder(i18n.get("label.target.filter.count")); message.append(managementUIState.getTargetsCountAll()); message.append(HawkbitCommonUtil.SP_STRING_SPACE); - if (totalTargetTableEnteries > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { + if (totalTargetTableEnteries > SPUIDefinitions.MAX_TABLE_ENTRIES) { message.append(i18n.get("label.filter.shown")); - message.append(SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + message.append(SPUIDefinitions.MAX_TABLE_ENTRIES); } else { if (!targFilParams.hasFilter()) { message.append(i18n.get("label.filter.shown")); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java index 1a9d3572f..e4c56b165 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java @@ -387,7 +387,6 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin managementUIState.getTargetTableFilters().getPinnedDistId() .ifPresent(distId -> unPinDeletedDS(deletedIds, distId)); - eventBus.publish(this, SaveActionWindowEvent.DELETED_DISTRIBUTIONS); managementUIState.getDeletedDistributionList().clear(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index aa9f346a1..6c08896c1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -190,9 +190,9 @@ public class TargetBeanQuery extends AbstractBeanQuery { final ManagementUIState tmpManagementUIState = getManagementUIState(); tmpManagementUIState.setTargetsCountAll(totSize); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - tmpManagementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); - size = SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES; + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + tmpManagementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); + size = SPUIDefinitions.MAX_TABLE_ENTRIES; } else { tmpManagementUIState.setTargetsTruncated(null); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java index 4e43ea39b..ec0ad0c55 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java @@ -17,11 +17,12 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetInfo; @@ -142,6 +143,8 @@ public class TargetTable extends AbstractTable { onTargetInfoUpdateEvents((List) events); } else if (TargetDeletedEvent.class.isInstance(firstEvent)) { onTargetDeletedEvent((List) events); + } else if(TargetUpdatedEvent.class.isInstance(firstEvent)){ + onTargetUpdateEvents((List) events); } } @@ -809,7 +812,7 @@ public class TargetTable extends AbstractTable { private void refreshTargets() { final LazyQueryContainer targetContainer = (LazyQueryContainer) getContainerDataSource(); final int size = targetContainer.size(); - if (size < SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { + if (size < SPUIDefinitions.MAX_TABLE_ENTRIES) { refreshTablecontainer(); } else { // If table is not refreshed , explicitly target total count and @@ -829,10 +832,12 @@ public class TargetTable extends AbstractTable { final TargetIdName targetIdName) { final LazyQueryContainer targetContainer = (LazyQueryContainer) getContainerDataSource(); final Item item = targetContainer.getItem(targetIdName); - item.getItemProperty(SPUILabelDefinitions.VAR_TARGET_STATUS).setValue(targetInfo.getUpdateStatus()); item.getItemProperty(SPUILabelDefinitions.VAR_NAME).setValue(target.getName()); - item.getItemProperty(SPUILabelDefinitions.VAR_POLL_STATUS_TOOL_TIP) - .setValue(HawkbitCommonUtil.getPollStatusToolTip(targetInfo.getPollStatus(), i18n)); + if (targetInfo != null) { + item.getItemProperty(SPUILabelDefinitions.VAR_POLL_STATUS_TOOL_TIP).setValue( + HawkbitCommonUtil.getPollStatusToolTip(targetInfo.getPollStatus(), i18n)); + item.getItemProperty(SPUILabelDefinitions.VAR_TARGET_STATUS).setValue(targetInfo.getUpdateStatus()); + } } private boolean isLastSelectedTarget(final TargetIdName targetIdName) { @@ -879,6 +884,35 @@ public class TargetTable extends AbstractTable { } } + + private void onTargetUpdateEvents(List events) { + final List visibleItemIds = (List) getVisibleItemIds(); + boolean shoulTargetsUpdated = false; + Target lastSelectedTarget = null; + for (final TargetUpdatedEvent targetUpdatedEvent : events) { + Target target = targetUpdatedEvent.getEntity(); + final TargetIdName targetIdName = target.getTargetIdName(); + if (Filters.or(getTargetTableFilters(target)).doFilter()) { + shoulTargetsUpdated = true; + } else { + if (visibleItemIds.contains(targetIdName)) { + updateVisibleItemOnEvent(null, target, targetIdName); + } + } + if (isLastSelectedTarget(targetIdName)) { + lastSelectedTarget = target; + } + } + if (shoulTargetsUpdated) { + refreshTargets(); + } + if (lastSelectedTarget != null) { + eventBus.publish(this, new TargetTableEvent(BaseEntityEventType.SELECTED_ENTITY, lastSelectedTarget)); + } + } + + + private void onTargetCreatedEvents() { refreshTargets(); } @@ -954,8 +988,8 @@ public class TargetTable extends AbstractTable { size = getTargetsCountWithFilter(totalTargetsCount, status, targetTags, distributionId, searchText, noTagClicked, pinnedDistId); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - managementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + managementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java index 685be685e..487f05ae5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java @@ -140,9 +140,9 @@ public class RolloutGroupTargetsBeanQuery extends AbstractBeanQuery size = firstPageTargetSets.getTotalElements(); } getRolloutUIState().setRolloutGroupTargetsTotalCount(size); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - getRolloutUIState().setRolloutGroupTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); - return SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES; + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + getRolloutUIState().setRolloutGroupTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); + return SPUIDefinitions.MAX_TABLE_ENTRIES; } return (int) size; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java index c791a0eb2..e5c716e83 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java @@ -94,7 +94,7 @@ public class RolloutGroupTargetsCountLabelMessage extends Label { // set the icon setIcon(FontAwesome.INFO_CIRCLE); setDescription(i18n.get("rollout.group.label.target.truncated", - rolloutUIState.getRolloutGroupTargetsTruncated(), SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES)); + rolloutUIState.getRolloutGroupTargetsTruncated(), SPUIDefinitions.MAX_TABLE_ENTRIES)); totalTargetTableEnteries += rolloutUIState.getRolloutGroupTargetsTruncated(); } else { setIcon(null); @@ -104,9 +104,9 @@ public class RolloutGroupTargetsCountLabelMessage extends Label { final StringBuilder message = new StringBuilder(i18n.get("label.target.filter.count")); message.append(rolloutUIState.getRolloutGroupTargetsTotalCount()); message.append(HawkbitCommonUtil.SP_STRING_SPACE); - if (totalTargetTableEnteries > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { + if (totalTargetTableEnteries > SPUIDefinitions.MAX_TABLE_ENTRIES) { message.append(i18n.get("label.filter.shown")); - message.append(SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + message.append(SPUIDefinitions.MAX_TABLE_ENTRIES); } else { message.append(i18n.get("label.filter.shown")); message.append(rolloutGroupTargetsListGrid.getContainerDataSource().size()); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java index f035c4995..5d1248681 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java @@ -273,10 +273,6 @@ public final class SPUIDefinitions { * New Target save icon id. */ public static final String NEW_TARGET_SAVE = "target.add.save"; - /** - * New Target discard icon id. - */ - // public static final String NEW_TARGET_DISCARD = "target.add.discard"; /** * New Target add icon id. */ @@ -861,7 +857,7 @@ public final class SPUIDefinitions { * truncates it. This protects to endless scroll to very high page numbers * which is very in performant. */ - public static final int MAX_TARGET_TABLE_ENTRIES = 5000; + public static final int MAX_TABLE_ENTRIES = 5000; /** * New software module set type add icon id.