Merge branch 'master' into Feature/Add_Rest_Api_with_Java_client

Conflicts:
	examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/Start.java
	examples/hawkbit-mgmt-api-client/pom.xml
	examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java
	examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java
	examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java
	examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java
	examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java
	examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java
	examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java
	hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java
	hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java
	hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/BaseSwModuleBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTable.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTableHeader.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/ProxyTarget.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUIComponentProvider.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/CreateUpdateDistSetTypeLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/ManageDistBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterHeader.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterTable.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterManagementView.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/event/CustomFilterUIEvent.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/LoginView.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/CreateUpdateDistributionTagLayoutWindow.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/DistributionTagButtons.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/tag/CreateUpdateTagLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAddUpdateWindowLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/CreateUpdateTargetTagLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/TargetTagFilterButtons.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/AddUpdateRolloutWindowLayout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/DistributionBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/ProxyRollout.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutListGrid.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/ProxyRolloutGroup.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupListGrid.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupsListHeader.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/AuthenticationConfigurationView.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/HawkbitCommonUtil.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPDateTimeUtil.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponetIdProvider.java
	hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/common.scss
	hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss
	hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/rollout.scss
	hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss
	hawkbit-ui/src/main/resources/messages.properties
	hawkbit-ui/src/main/resources/messages_de.properties
	hawkbit-ui/src/main/resources/messages_en.properties


Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>
This commit is contained in:
SirWayne
2016-05-17 11:16:18 +02:00
166 changed files with 2700 additions and 1284 deletions

View File

@@ -22,14 +22,17 @@ import org.springframework.context.annotation.Import;
@SpringBootApplication @SpringBootApplication
@Import({ RepositoryApplicationConfiguration.class }) @Import({ RepositoryApplicationConfiguration.class })
@EnableHawkbitManagedSecurityConfiguration @EnableHawkbitManagedSecurityConfiguration
// Exception squid:S1118 - Spring boot standard behavior
@SuppressWarnings({ "squid:S1118" })
public class Start { public class Start {
/** /**
* Main method to start the spring-boot application. * Main method to start the spring-boot application.
* *
* @param args * @param args
* the VM arguments. * the VM arguments.
*/ */
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) { public static void main(final String[] args) {
SpringApplication.run(Start.class, args); SpringApplication.run(Start.class, args);
} }

View File

@@ -1,4 +1,3 @@
<?xml version="1.0"?>
<!-- <!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others. Copyright (c) 2015 Bosch Software Innovations GmbH and others.
@@ -9,7 +8,8 @@
http://www.eclipse.org/legal/epl-v10.html http://www.eclipse.org/legal/epl-v10.html
--> -->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" <project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
@@ -133,13 +133,17 @@
<artifactId>spring-boot-configuration-processor</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies> </dependencies>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.vaadin</groupId> <groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId> <artifactId>vaadin-bom</artifactId>
<version>7.6.3</version> <version>${vaadin.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>

View File

@@ -8,6 +8,8 @@
*/ */
package org.eclipse.hawkbit.simulator; package org.eclipse.hawkbit.simulator;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
/** /**
* The bean of a simulated device which can be stored in the * The bean of a simulated device which can be stored in the
* {@link DeviceSimulatorRepository} or shown in the UI. * {@link DeviceSimulatorRepository} or shown in the UI.
@@ -22,16 +24,15 @@ public abstract class AbstractSimulatedDevice {
private Status status; private Status status;
private double progress; private double progress;
private String swversion = "unknown"; private String swversion = "unknown";
private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL; private UpdateStatus updateStatus = new UpdateStatus(ResponseStatus.SUCCESSFUL, "Simulation complete!");
private Protocol protocol = Protocol.DMF_AMQP; private Protocol protocol = Protocol.DMF_AMQP;
private String targetSecurityToken;
private int nextPollCounterSec; private int nextPollCounterSec;
/** /**
* Enum definition of the protocol to be used for the simulated device. * Enum definition of the protocol to be used for the simulated device.
* *
* @author Michael Hirsch
*
*/ */
public enum Protocol { public enum Protocol {
/** /**
@@ -69,24 +70,6 @@ public abstract class AbstractSimulatedDevice {
ERROR; ERROR;
} }
/**
* The status to response to the hawkbit update server if an simulated
* update process should be respond with successful or failure update.
*
* @author Michael Hirsch
*
*/
public enum ResponseStatus {
/**
* updated has been successful and response the successful update.
*/
SUCCESSFUL,
/**
* updated has been not successful and response the error update.
*/
ERROR;
}
/** /**
* empty constructor. * empty constructor.
*/ */
@@ -158,12 +141,12 @@ public abstract class AbstractSimulatedDevice {
this.swversion = swversion; this.swversion = swversion;
} }
public ResponseStatus getResponseStatus() { public UpdateStatus getUpdateStatus() {
return responseStatus; return updateStatus;
} }
public void setResponseStatus(final ResponseStatus responseStatus) { public void setUpdateStatus(final UpdateStatus updateStatus) {
this.responseStatus = responseStatus; this.updateStatus = updateStatus;
} }
public Protocol getProtocol() { public Protocol getProtocol() {
@@ -177,4 +160,13 @@ public abstract class AbstractSimulatedDevice {
public void setNextPollCounterSec(final int nextPollDelayInSec) { public void setNextPollCounterSec(final int nextPollDelayInSec) {
this.nextPollCounterSec = nextPollDelayInSec; this.nextPollCounterSec = nextPollDelayInSec;
} }
public String getTargetSecurityToken() {
return targetSecurityToken;
}
public void setTargetSecurityToken(final String targetSecurityToken) {
this.targetSecurityToken = targetSecurityToken;
}
} }

View File

@@ -8,8 +8,6 @@
*/ */
package org.eclipse.hawkbit.simulator; package org.eclipse.hawkbit.simulator;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.eclipse.hawkbit.simulator.http.ControllerResource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -18,7 +16,7 @@ import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException; import com.jayway.jsonpath.PathNotFoundException;
/** /**
* @author Michael Hirsch * A simulated device using the DDI API of the hawkBit update server.
* *
*/ */
public class DDISimulatedDevice extends AbstractSimulatedDevice { public class DDISimulatedDevice extends AbstractSimulatedDevice {
@@ -26,12 +24,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class); private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class);
private final int pollDelaySec; private final int pollDelaySec;
private final ScheduledExecutorService pollthreadpool;
private final ControllerResource controllerResource; private final ControllerResource controllerResource;
private final DeviceSimulatorUpdater deviceUpdater;
private volatile boolean removed; private volatile boolean removed;
private volatile Long currentActionId; private volatile Long currentActionId;
private final DeviceSimulatorUpdater deviceUpdater;
/** /**
* @param id * @param id
@@ -42,18 +40,14 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
* the delay of the poll interval in sec * the delay of the poll interval in sec
* @param controllerResource * @param controllerResource
* the http controller resource * the http controller resource
* @param pollthreadpool
* the threadpool for polling endpoint
* @param deviceUpdater * @param deviceUpdater
* the service to update devices * the service to update devices
*/ */
public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec, public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec,
final ControllerResource controllerResource, final ScheduledExecutorService pollthreadpool, final ControllerResource controllerResource, final DeviceSimulatorUpdater deviceUpdater) {
final DeviceSimulatorUpdater deviceUpdater) {
super(id, tenant, Protocol.DDI_HTTP); super(id, tenant, Protocol.DDI_HTTP);
this.pollDelaySec = pollDelaySec; this.pollDelaySec = pollDelaySec;
this.controllerResource = controllerResource; this.controllerResource = controllerResource;
this.pollthreadpool = pollthreadpool;
this.deviceUpdater = deviceUpdater; this.deviceUpdater = deviceUpdater;
setNextPollCounterSec(pollDelaySec); setNextPollCounterSec(pollDelaySec);
} }
@@ -76,27 +70,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
final String basePollJson = controllerResource.get(getTenant(), getId()); final String basePollJson = controllerResource.get(getTenant(), getId());
try { try {
final String href = JsonPath.parse(basePollJson).read("_links.deploymentBase.href"); final String href = JsonPath.parse(basePollJson).read("_links.deploymentBase.href");
final long actionId = Long.parseLong(href.substring(href.lastIndexOf("/") + 1, href.indexOf("?"))); final long actionId = Long.parseLong(href.substring(href.lastIndexOf('/') + 1, href.indexOf('?')));
if (currentActionId == null) { if (currentActionId == null) {
final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId); final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId);
final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version"); final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version");
currentActionId = actionId; currentActionId = actionId;
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, (device, actionId1) -> { startDdiUpdate(actionId, swVersion);
switch (device.getResponseStatus()) {
case SUCCESSFUL:
controllerResource.postSuccessFeedback(getTenant(), getId(),
actionId1);
break;
case ERROR:
controllerResource.postErrorFeedback(getTenant(), getId(),
actionId1);
break;
default:
throw new IllegalStateException(
"simulated device has an unknown response status + " + device.getResponseStatus());
}
currentActionId = null;
});
} }
} catch (final PathNotFoundException e) { } catch (final PathNotFoundException e) {
// href might not be in the json response, so ignore // href might not be in the json response, so ignore
@@ -106,4 +85,21 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice {
} }
} }
private void startDdiUpdate(final long actionId, final String swVersion) {
deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, null, null, (device, actionId1) -> {
switch (device.getUpdateStatus().getResponseStatus()) {
case SUCCESSFUL:
controllerResource.postSuccessFeedback(getTenant(), getId(), actionId1);
break;
case ERROR:
controllerResource.postErrorFeedback(getTenant(), getId(), actionId1);
break;
default:
throw new IllegalStateException("simulated device has an unknown response status + "
+ device.getUpdateStatus().getResponseStatus());
}
currentActionId = null;
});
}
} }

View File

@@ -9,10 +9,7 @@
package org.eclipse.hawkbit.simulator; package org.eclipse.hawkbit.simulator;
/** /**
* An simulated device using the DMF API of the hawkbit update server. * A simulated device using the DMF API of the hawkBit update server.
*
* @author Michael Hirsch
*
*/ */
public class DMFSimulatedDevice extends AbstractSimulatedDevice { public class DMFSimulatedDevice extends AbstractSimulatedDevice {

View File

@@ -21,8 +21,6 @@ import com.vaadin.spring.annotation.EnableVaadin;
/** /**
* The main-method to start the Spring-Boot application. * The main-method to start the Spring-Boot application.
* *
*
*
*/ */
@SpringBootApplication @SpringBootApplication
@EnableVaadin @EnableVaadin
@@ -46,6 +44,8 @@ public class DeviceSimulator {
* @param args * @param args
* the args * the args
*/ */
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) { public static void main(final String[] args) {
SpringApplication.run(DeviceSimulator.class, args); SpringApplication.run(DeviceSimulator.class, args);
} }

View File

@@ -8,27 +8,56 @@
*/ */
package org.eclipse.hawkbit.simulator; package org.eclipse.hawkbit.simulator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.DigestOutputStream;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.eclipse.hawkbit.dmf.json.model.Artifact;
import org.eclipse.hawkbit.dmf.json.model.SoftwareModule;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate; import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate; import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.EventBus;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
/** /**
* @author Michael Hirsch * Update simulation handler.
* *
*/ */
@Service @Service
public class DeviceSimulatorUpdater { public class DeviceSimulatorUpdater {
private static final Logger LOGGER = LoggerFactory.getLogger(DeviceSimulatorUpdater.class);
private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4); private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4);
@@ -54,14 +83,18 @@ public class DeviceSimulatorUpdater {
* @param actionId * @param actionId
* the actionId from the hawkbit update server to start the * the actionId from the hawkbit update server to start the
* update. * update.
* @param swVersion * @param modules
* the software module version from the hawkbit update server * the software module version from the hawkbit update server
* @param swVersion
* the software version as static value in case modules is null
* @param targetSecurityToken
* the target security token for download authentication
* @param callback * @param callback
* the callback which gets called when the simulated update * the callback which gets called when the simulated update
* process has been finished * process has been finished
*/ */
public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion, public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion,
final UpdaterCallback callback) { final List<SoftwareModule> modules, final String targetSecurityToken, final UpdaterCallback callback) {
AbstractSimulatedDevice device = repository.get(tenant, id); AbstractSimulatedDevice device = repository.get(tenant, id);
// plug and play - non existing device will be auto created // plug and play - non existing device will be auto created
@@ -70,14 +103,23 @@ public class DeviceSimulatorUpdater {
} }
device.setProgress(0.0); device.setProgress(0.0);
device.setSwversion(swVersion);
if (modules == null || modules.isEmpty()) {
device.setSwversion(swVersion);
} else {
device.setSwversion(modules.stream().map(sm -> sm.getModuleVersion()).collect(Collectors.joining(", ")));
}
device.setTargetSecurityToken(targetSecurityToken);
eventbus.post(new InitUpdate(device)); eventbus.post(new InitUpdate(device));
threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), threadPool.schedule(
2_000, TimeUnit.MILLISECONDS); new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules), 2_000,
TimeUnit.MILLISECONDS);
} }
private static final class DeviceSimulatorUpdateThread implements Runnable { private static final class DeviceSimulatorUpdateThread implements Runnable {
private static final int MINIMUM_TOKENLENGTH_FOR_HINT = 6;
private static final Random rndSleep = new SecureRandom(); private static final Random rndSleep = new SecureRandom();
private final AbstractSimulatedDevice device; private final AbstractSimulatedDevice device;
@@ -85,38 +127,205 @@ public class DeviceSimulatorUpdater {
private final long actionId; private final long actionId;
private final EventBus eventbus; private final EventBus eventbus;
private final UpdaterCallback callback; private final UpdaterCallback callback;
private final List<SoftwareModule> modules;
private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService, private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService,
final long actionId, final EventBus eventbus, final UpdaterCallback callback) { final long actionId, final EventBus eventbus, final UpdaterCallback callback,
final List<SoftwareModule> modules) {
this.device = device; this.device = device;
this.spSenderService = spSenderService; this.spSenderService = spSenderService;
this.actionId = actionId; this.actionId = actionId;
this.eventbus = eventbus; this.eventbus = eventbus;
this.callback = callback; this.callback = callback;
this.modules = modules;
} }
@Override @Override
public void run() { public void run() {
if (device.getProgress() <= 0 && modules != null) {
device.setUpdateStatus(simulateDownloads(device.getTargetSecurityToken()));
if (isErrorResponse(device.getUpdateStatus())) {
callback.updateFinished(device, actionId);
eventbus.post(new ProgressUpdate(device));
return;
}
}
final double newProgress = device.getProgress() + 0.2; final double newProgress = device.getProgress() + 0.2;
device.setProgress(newProgress); device.setProgress(newProgress);
if (newProgress < 1.0) { if (newProgress < 1.0) {
threadPool.schedule( threadPool.schedule(
new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules),
rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS); rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS);
} else { } else {
callback.updateFinished(device, actionId); callback.updateFinished(device, actionId);
} }
eventbus.post(new ProgressUpdate(device)); eventbus.post(new ProgressUpdate(device));
} }
private UpdateStatus simulateDownloads(final String targetToken) {
final List<UpdateStatus> status = new ArrayList<>();
LOGGER.info("Simulate downloads for {}", device.getId());
modules.forEach(module -> module.getArtifacts()
.forEach(artifact -> handleArtifacts(targetToken, status, artifact)));
final UpdateStatus result = new UpdateStatus(ResponseStatus.SUCCESSFUL);
result.getStatusMessages().add("Simulation complete!");
status.forEach(download -> {
result.getStatusMessages().addAll(download.getStatusMessages());
if (isErrorResponse(download)) {
result.setResponseStatus(ResponseStatus.ERROR);
}
});
LOGGER.info("Download simulations complete for {}", device.getId());
return result;
}
private boolean isErrorResponse(final UpdateStatus status) {
if (status == null) {
return false;
}
return ResponseStatus.ERROR.equals(status.getResponseStatus());
}
private static void handleArtifacts(final String targetToken, final List<UpdateStatus> status,
final Artifact artifact) {
artifact.getUrls().entrySet().forEach(entry -> {
switch (entry.getKey()) {
case HTTP:
case HTTPS:
status.add(downloadUrl(entry.getValue(), targetToken, artifact.getHashes().getSha1(),
artifact.getSize()));
break;
default:
// not supported yet
break;
}
});
}
private static UpdateStatus downloadUrl(final String url, final String targetToken, final String sha1Hash,
final long size) {
LOGGER.debug("Downloading {} with token {}, expected sha1 hash {} and size {}", url,
hideTokenDetails(targetToken), sha1Hash, size);
long overallread = 0;
try {
final CloseableHttpClient httpclient = createHttpClientThatAcceptsAllServerCerts();
final HttpGet request = new HttpGet(url);
request.addHeader(HttpHeaders.AUTHORIZATION, "TargetToken " + targetToken);
final String sha1HashResult;
try (final CloseableHttpResponse response = httpclient.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
final String message = wrongStatusCode(url, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
if (response.getEntity().getContentLength() != size) {
final String message = wrongContentLength(url, size, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
final File tempFile = File.createTempFile("uploadFile", null);
final MessageDigest md = MessageDigest.getInstance("SHA-1");
try (final DigestOutputStream dos = new DigestOutputStream(new FileOutputStream(tempFile), md)) {
try (final BufferedOutputStream bdos = new BufferedOutputStream(dos)) {
try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
overallread = ByteStreams.copy(bis, bdos);
}
}
} finally {
if (tempFile != null && !tempFile.delete()) {
LOGGER.error("Could not delete temporary file: {}", tempFile);
}
}
if (overallread != size) {
final String message = incompleteRead(url, size, overallread);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
sha1HashResult = BaseEncoding.base16().lowerCase().encode(md.digest());
}
if (!sha1Hash.equalsIgnoreCase(sha1HashResult)) {
final String message = wrongHash(url, sha1Hash, overallread, sha1HashResult);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
} catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
LOGGER.error("Failed to download {} with {}", url, e.getMessage());
return new UpdateStatus(ResponseStatus.ERROR, "Failed to download " + url + ": " + e.getMessage());
}
final String message = "Downloaded " + url + " (" + overallread + " bytes)";
LOGGER.debug(message);
return new UpdateStatus(ResponseStatus.SUCCESSFUL, message);
}
private static String hideTokenDetails(final String targetToken) {
if (targetToken.isEmpty()) {
return "<EMTPTY!>";
}
if (targetToken.length() <= MINIMUM_TOKENLENGTH_FOR_HINT) {
return "***";
}
return targetToken.substring(0, 2) + "***"
+ targetToken.substring(targetToken.length() - 2, targetToken.length());
}
private static String wrongHash(final String url, final String sha1Hash, final long overallread,
final String sha1HashResult) {
final String message = "Download " + url + " failed with SHA1 hash missmatch (Expected: " + sha1Hash
+ " but got: " + sha1HashResult + ") (" + overallread + " bytes)";
LOGGER.error(message);
return message;
}
private static String incompleteRead(final String url, final long size, final long overallread) {
final String message = "Download " + url + " is incomplete (Expected: " + size + " but got: " + overallread
+ ")";
LOGGER.error(message);
return message;
}
private static String wrongContentLength(final String url, final long size,
final CloseableHttpResponse response) {
final String message = "Download " + url + " has wrong content length (Expected: " + size + " but got: "
+ response.getEntity().getContentLength() + ")";
LOGGER.error(message);
return message;
}
private static String wrongStatusCode(final String url, final CloseableHttpResponse response) {
final String message = "Download " + url + " failed (" + response.getStatusLine().getStatusCode() + ")";
LOGGER.error(message);
return message;
}
private static CloseableHttpClient createHttpClientThatAcceptsAllServerCerts()
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
final SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, (chain, authType) -> true);
final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
} }
/** /**
* Callback interface which is called when the simulated update process has * Callback interface which is called when the simulated update process has
* been finished and the caller of starting the simulated update process can * been finished and the caller of starting the simulated update process can
* send the result to the hawkbit update server back. * send the result back to the hawkBit update server.
*
* @author Michael Hirsch
*
*/ */
@FunctionalInterface @FunctionalInterface
public interface UpdaterCallback { public interface UpdaterCallback {

View File

@@ -26,9 +26,6 @@ import com.google.common.eventbus.EventBus;
/** /**
* Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every * Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every
* second. * second.
*
* @author Michael Hirsch
*
*/ */
@Component @Component
public class NextPollTimeController { public class NextPollTimeController {
@@ -59,16 +56,15 @@ public class NextPollTimeController {
devices.forEach(device -> { devices.forEach(device -> {
int nextCounter = device.getNextPollCounterSec() - 1; int nextCounter = device.getNextPollCounterSec() - 1;
if (nextCounter < 0) { if (nextCounter < 0 && device instanceof DDISimulatedDevice) {
if (device instanceof DDISimulatedDevice) { try {
try { pollService.submit(() -> ((DDISimulatedDevice) device).poll());
pollService.submit(() -> ((DDISimulatedDevice) device).poll()); } catch (final IllegalStateException e) {
} catch (final IllegalStateException e) { LOGGER.trace("Device could not be polled", e);
LOGGER.trace("Device could not be polled", e);
}
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
} }
nextCounter = ((DDISimulatedDevice) device).getPollDelaySec();
} }
device.setNextPollCounterSec(nextCounter); device.setNextPollCounterSec(nextCounter);
}); });
eventBus.post(new NextPollCounterUpdate(devices)); eventBus.post(new NextPollCounterUpdate(devices));

View File

@@ -9,8 +9,6 @@
package org.eclipse.hawkbit.simulator; package org.eclipse.hawkbit.simulator;
import java.net.URL; import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.eclipse.hawkbit.simulator.http.ControllerResource;
@@ -24,15 +22,9 @@ import feign.Logger;
/** /**
* The simulated device factory to create either {@link DMFSimulatedDevice} or * The simulated device factory to create either {@link DMFSimulatedDevice} or
* {@link DDISimulatedDevice#}. * {@link DDISimulatedDevice#}.
*
* @author Michael Hirsch
*
*/ */
@Service @Service
public class SimulatedDeviceFactory { public class SimulatedDeviceFactory {
private static final ScheduledExecutorService pollThreadPool = Executors.newScheduledThreadPool(4);
@Autowired @Autowired
private DeviceSimulatorUpdater deviceUpdater; private DeviceSimulatorUpdater deviceUpdater;
@@ -47,7 +39,8 @@ public class SimulatedDeviceFactory {
* the protocol of the device * the protocol of the device
* @return the created simulated device * @return the created simulated device
*/ */
public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol) { public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant,
final Protocol protocol) {
return createSimulatedDevice(id, tenant, protocol, 30, null, null); return createSimulatedDevice(id, tenant, protocol, 30, null, null);
} }
@@ -80,7 +73,7 @@ public class SimulatedDeviceFactory {
final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger()) final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger())
.requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC) .requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC)
.target(ControllerResource.class, baseEndpoint.toString()); .target(ControllerResource.class, baseEndpoint.toString());
return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, pollThreadPool, deviceUpdater); return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, deviceUpdater);
default: default:
throw new IllegalArgumentException("Protocol " + protocol + " unknown"); throw new IllegalArgumentException("Protocol " + protocol + " unknown");
} }

View File

@@ -86,7 +86,10 @@ public class SimulationController {
final String deviceId = name + i; final String deviceId = name + i;
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint), repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint),
gatewayToken)); gatewayToken));
spSenderService.createOrUpdateThing(tenant, deviceId);
if (protocol == Protocol.DMF_AMQP) {
spSenderService.createOrUpdateThing(tenant, deviceId);
}
} }
return ResponseEntity.ok("Updated " + amount + " DMF connected targets!"); return ResponseEntity.ok("Updated " + amount + " DMF connected targets!");

View File

@@ -11,10 +11,12 @@ package org.eclipse.hawkbit.simulator;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -24,6 +26,7 @@ import org.springframework.stereotype.Component;
* *
*/ */
@Component @Component
@ConditionalOnProperty(prefix = "hawkbit.device.simulator", name = "autostart", matchIfMissing = true)
public class SimulatorStartup implements ApplicationListener<ContextRefreshedEvent> { public class SimulatorStartup implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorStartup.class); private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorStartup.class);
@@ -52,7 +55,9 @@ public class SimulatorStartup implements ApplicationListener<ContextRefreshedEve
LOGGER.error("Creation of simulated device at startup failed.", e); LOGGER.error("Creation of simulated device at startup failed.", e);
} }
spSenderService.createOrUpdateThing(autostart.getTenant(), deviceId); if (autostart.getApi() == Protocol.DMF_AMQP) {
spSenderService.createOrUpdateThing(autostart.getTenant(), deviceId);
}
} }
}); });
} }

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.simulator;
import java.util.ArrayList;
import java.util.List;
/**
* Update status of the simulated update.
*
*/
public class UpdateStatus {
private ResponseStatus responseStatus;
private List<String> statusMessages;
/**
* Constructor.
*
* @param responseStatus
* of the update
*/
public UpdateStatus(final ResponseStatus responseStatus) {
this.responseStatus = responseStatus;
}
/**
* Constructor including status message.
*
* @param responseStatus
* of the update
* @param message
* of the update status
*/
public UpdateStatus(final ResponseStatus responseStatus, final String message) {
this(responseStatus);
statusMessages = new ArrayList<>();
statusMessages.add(message);
}
public ResponseStatus getResponseStatus() {
return responseStatus;
}
public void setResponseStatus(final ResponseStatus responseStatus) {
this.responseStatus = responseStatus;
}
public List<String> getStatusMessages() {
if (statusMessages == null) {
statusMessages = new ArrayList<>();
}
return statusMessages;
}
/**
* The status to response to the hawkBit update server if an simulated
* update process should be respond with successful or failure update.
*/
public enum ResponseStatus {
/**
* Update has been successful and response the successful update.
*/
SUCCESSFUL,
/**
* Update has been not successful and response the error update.
*/
ERROR;
}
}

View File

@@ -39,6 +39,12 @@ public class AmqpProperties {
*/ */
private String deadLetterExchange = "simulator.deadletter"; private String deadLetterExchange = "simulator.deadletter";
/**
* Message time to live (ttl) for the deadletter queue. Default ttl is 1
* hour.
*/
private int deadLetterTtl = 60_000;
public String getReceiverConnectorQueueFromSp() { public String getReceiverConnectorQueueFromSp() {
return receiverConnectorQueueFromSp; return receiverConnectorQueueFromSp;
} }
@@ -70,4 +76,12 @@ public class AmqpProperties {
public void setSenderForSpExchange(final String senderForSpExchange) { public void setSenderForSpExchange(final String senderForSpExchange) {
this.senderForSpExchange = senderForSpExchange; this.senderForSpExchange = senderForSpExchange;
} }
public int getDeadLetterTtl() {
return deadLetterTtl;
}
public void setDeadLetterTtl(final int deadLetterTtl) {
this.deadLetterTtl = deadLetterTtl;
}
} }

View File

@@ -25,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.google.common.collect.Lists;
/** /**
* Handle all incoming Messages from hawkBit update server. * Handle all incoming Messages from hawkBit update server.
* *
@@ -88,6 +90,8 @@ public class SpReceiverService extends ReceiverService {
if (eventHeader == null) { if (eventHeader == null) {
logAndThrowMessageError(message, "Event Topic is not set"); logAndThrowMessageError(message, "Event Topic is not set");
} }
// Exception squid:S2259 - Checked before
@SuppressWarnings({ "squid:S2259" })
final EventTopic eventTopic = EventTopic.valueOf(eventHeader.toString()); final EventTopic eventTopic = EventTopic.valueOf(eventHeader.toString());
switch (eventTopic) { switch (eventTopic) {
case DOWNLOAD_AND_INSTALL: case DOWNLOAD_AND_INSTALL:
@@ -109,7 +113,7 @@ public class SpReceiverService extends ReceiverService {
final Long actionId = convertMessage(message, Long.class); final Long actionId = convertMessage(message, Long.class);
final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId); final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId);
spSenderService.finishUpdateProcess(update, "Simulation canceled"); spSenderService.finishUpdateProcess(update, Lists.newArrayList("Simulation canceled"));
} }
private void handleUpdateProcess(final Message message, final String thingId) { private void handleUpdateProcess(final Message message, final String thingId) {
@@ -120,19 +124,20 @@ public class SpReceiverService extends ReceiverService {
final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message, final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message,
DownloadAndUpdateRequest.class); DownloadAndUpdateRequest.class);
final Long actionId = downloadAndUpdateRequest.getActionId(); final Long actionId = downloadAndUpdateRequest.getActionId();
final String targetSecurityToken = downloadAndUpdateRequest.getTargetSecurityToken();
deviceUpdater.startUpdate(tenant, thingId, actionId, deviceUpdater.startUpdate(tenant, thingId, actionId, null, downloadAndUpdateRequest.getSoftwareModules(),
downloadAndUpdateRequest.getSoftwareModules().get(0).getModuleVersion(), (device, actionId1) -> { targetSecurityToken, (device, actionId1) -> {
switch (device.getResponseStatus()) { switch (device.getUpdateStatus().getResponseStatus()) {
case SUCCESSFUL: case SUCCESSFUL:
spSenderService.finishUpdateProcess( spSenderService.finishUpdateProcess(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete!"); device.getUpdateStatus().getStatusMessages());
break; break;
case ERROR: case ERROR:
spSenderService.finishUpdateProcessWithError( spSenderService.finishUpdateProcessWithError(
new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), new SimulatedUpdate(device.getTenant(), device.getId(), actionId1),
"Simulation complete with error!"); device.getUpdateStatus().getStatusMessages());
break; break;
default: default:
break; break;

View File

@@ -8,6 +8,7 @@
*/ */
package org.eclipse.hawkbit.simulator.amqp; package org.eclipse.hawkbit.simulator.amqp;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings; import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
@@ -23,13 +24,9 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
/** /**
* Sender service to send message to SP. * Sender service to send messages to update server.
*
*
*
*/ */
@Service @Service
public class SpSenderService extends SenderService { public class SpSenderService extends SenderService {
@@ -59,8 +56,9 @@ public class SpSenderService extends SenderService {
* @param description * @param description
* a description according the update process * a description according the update process
*/ */
public void finishUpdateProcess(final SimulatedUpdate update, final String description) { public void finishUpdateProcess(final SimulatedUpdate update, final List<String> updateResultMessages) {
final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED, description); final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED,
updateResultMessages);
sendMessage(spExchange, updateResultMessage); sendMessage(spExchange, updateResultMessage);
} }
@@ -72,9 +70,9 @@ public class SpSenderService extends SenderService {
* @param messageDescription * @param messageDescription
* a description according the update process * a description according the update process
*/ */
public void finishUpdateProcessWithError(final SimulatedUpdate update, final String messageDescription) { public void finishUpdateProcessWithError(final SimulatedUpdate update, final List<String> updateResultMessages) {
sendErrorgMessage(update, messageDescription); sendErrorgMessage(update, updateResultMessages);
LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", messageDescription, LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", updateResultMessages,
update.getThingId()); update.getThingId());
} }
@@ -88,8 +86,8 @@ public class SpSenderService extends SenderService {
* @param actionId * @param actionId
* the ID of the action for the error message * the ID of the action for the error message
*/ */
public void sendErrorMessage(final String tenant, final String messageDescription, final Long actionId) { public void sendErrorMessage(final String tenant, final List<String> updateResultMessages, final Long actionId) {
final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, messageDescription, actionId); final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, updateResultMessages, actionId);
sendMessage(spExchange, message); sendMessage(spExchange, message);
} }
@@ -101,8 +99,8 @@ public class SpSenderService extends SenderService {
* @param warningMessage * @param warningMessage
* a warning description * a warning description
*/ */
public void sendWarningMessage(final SimulatedUpdate update, final String warningMessage) { public void sendWarningMessage(final SimulatedUpdate update, final List<String> updateResultMessages) {
final Message message = createActionStatusMessage(update, warningMessage, ActionStatus.WARNING); final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.WARNING);
sendMessage(spExchange, message); sendMessage(spExchange, message);
} }
@@ -119,8 +117,8 @@ public class SpSenderService extends SenderService {
* the cached value * the cached value
*/ */
public void sendActionStatusMessage(final String tenant, final ActionStatus actionStatus, public void sendActionStatusMessage(final String tenant, final ActionStatus actionStatus,
final String actionMessage, final Long actionId) { final List<String> updateResultMessages, final Long actionId) {
final Message message = createActionStatusMessage(tenant, actionStatus, actionMessage, actionId); final Message message = createActionStatusMessage(tenant, actionStatus, updateResultMessages, actionId);
sendMessage(message); sendMessage(message);
} }
@@ -162,11 +160,11 @@ public class SpSenderService extends SenderService {
* *
* @param context * @param context
* the current context * the current context
* @param messageDescription * @param updateResultMessages
* a description according the update process * a list of descriptions according the update process
*/ */
private void sendErrorgMessage(final SimulatedUpdate update, final String messageDescription) { private void sendErrorgMessage(final SimulatedUpdate update, final List<String> updateResultMessages) {
final Message message = createActionStatusMessage(update, messageDescription, ActionStatus.ERROR); final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.ERROR);
sendMessage(spExchange, message); sendMessage(spExchange, message);
} }
@@ -183,7 +181,7 @@ public class SpSenderService extends SenderService {
* the cacheValue value * the cacheValue value
*/ */
private Message createActionStatusMessage(final String tenant, final ActionStatus actionStatus, private Message createActionStatusMessage(final String tenant, final ActionStatus actionStatus,
final String actionMessage, final Long actionId) { final List<String> updateResultMessages, final Long actionId) {
final MessageProperties messageProperties = new MessageProperties(); final MessageProperties messageProperties = new MessageProperties();
final Map<String, Object> headers = messageProperties.getHeaders(); final Map<String, Object> headers = messageProperties.getHeaders();
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
@@ -192,15 +190,14 @@ public class SpSenderService extends SenderService {
headers.put(MessageHeaderKey.TENANT, tenant); headers.put(MessageHeaderKey.TENANT, tenant);
headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON); headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON);
if (!StringUtils.isEmpty(actionMessage)) { actionUpdateStatus.getMessage().addAll(updateResultMessages);
actionUpdateStatus.getMessage().add(actionMessage);
}
actionUpdateStatus.setActionId(actionId); actionUpdateStatus.setActionId(actionId);
return convertMessage(actionUpdateStatus, messageProperties); return convertMessage(actionUpdateStatus, messageProperties);
} }
private Message createUpdateResultMessage(final SimulatedUpdate cacheValue, final ActionStatus actionStatus, private Message createUpdateResultMessage(final SimulatedUpdate cacheValue, final ActionStatus actionStatus,
final String updateResultMessage) { final List<String> updateResultMessages) {
final MessageProperties messageProperties = new MessageProperties(); final MessageProperties messageProperties = new MessageProperties();
final Map<String, Object> headers = messageProperties.getHeaders(); final Map<String, Object> headers = messageProperties.getHeaders();
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
@@ -209,14 +206,14 @@ public class SpSenderService extends SenderService {
headers.put(MessageHeaderKey.TENANT, cacheValue.getTenant()); headers.put(MessageHeaderKey.TENANT, cacheValue.getTenant());
headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON); headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON);
actionUpdateStatus.getMessage().add(updateResultMessage); actionUpdateStatus.getMessage().addAll(updateResultMessages);
actionUpdateStatus.setActionId(cacheValue.getActionId()); actionUpdateStatus.setActionId(cacheValue.getActionId());
return convertMessage(actionUpdateStatus, messageProperties); return convertMessage(actionUpdateStatus, messageProperties);
} }
private Message createActionStatusMessage(final SimulatedUpdate update, final String messageDescription, private Message createActionStatusMessage(final SimulatedUpdate update, final List<String> updateResultMessages,
final ActionStatus status) { final ActionStatus status) {
return createActionStatusMessage(update.getTenant(), status, messageDescription, update.getActionId()); return createActionStatusMessage(update.getTenant(), status, updateResultMessages, update.getActionId());
} }
} }

View File

@@ -13,8 +13,6 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
/** /**
* Event definition object which is published if the simulated device updated * Event definition object which is published if the simulated device updated
* its update progress. * its update progress.
*
* @author Michael Hirsch
* *
*/ */
public class ProgressUpdate { public class ProgressUpdate {

View File

@@ -8,21 +8,19 @@
*/ */
package org.eclipse.hawkbit.simulator.ui; package org.eclipse.hawkbit.simulator.ui;
import java.net.URL;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.ResponseStatus;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Status; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Status;
import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository; import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory; import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate; import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate; import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate; import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
import org.eclipse.hawkbit.simulator.ui.GenerateDialog.GenerateDialogCallback;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -52,13 +50,27 @@ import com.vaadin.ui.renderers.ProgressBarRenderer;
* Vaadin view which allows to generate devices through the DMF API and show the * Vaadin view which allows to generate devices through the DMF API and show the
* current simulated devices in a grid with their current status and update * current simulated devices in a grid with their current status and update
* progress. * progress.
*
* @author Michael Hirsch
* *
*/ */
@SpringView(name = "") @SpringView(name = "")
public class SimulatorView extends VerticalLayout implements View { public class SimulatorView extends VerticalLayout implements View {
private static final String NEXT_POLL_COUNTER_SEC_COL = "nextPollCounterSec";
private static final String RESPONSE_STATUS_COL = "responseStatus";
private static final String PROTOCOL_COL = "protocol";
private static final String TENANT_COL = "tenant";
private static final String PROGRESS_COL = "progress";
private static final String SWVERSION_COL = "swversion";
private static final String STATUS_COL = "status";
private static final String ID_COL = "id";
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Autowired @Autowired
@@ -79,6 +91,7 @@ public class SimulatorView extends VerticalLayout implements View {
private BeanContainer<String, AbstractSimulatedDevice> beanContainer; private BeanContainer<String, AbstractSimulatedDevice> beanContainer;
@SuppressWarnings("unchecked")
@Override @Override
public void enter(final ViewChangeEvent event) { public void enter(final ViewChangeEvent event) {
eventbus.register(this); eventbus.register(this);
@@ -91,7 +104,7 @@ public class SimulatorView extends VerticalLayout implements View {
createToolbar(); createToolbar();
beanContainer = new BeanContainer<>(AbstractSimulatedDevice.class); beanContainer = new BeanContainer<>(AbstractSimulatedDevice.class);
beanContainer.setBeanIdProperty("id"); beanContainer.setBeanIdProperty(ID_COL);
grid.setSizeFull(); grid.setSizeFull();
grid.setCellStyleGenerator(new CellStyleGenerator() { grid.setCellStyleGenerator(new CellStyleGenerator() {
@@ -100,28 +113,28 @@ public class SimulatorView extends VerticalLayout implements View {
@Override @Override
public String getStyle(final CellReference cellReference) { public String getStyle(final CellReference cellReference) {
return cellReference.getPropertyId().equals("status") ? "centeralign" : null; return cellReference.getPropertyId().equals(STATUS_COL) ? "centeralign" : null;
} }
}); });
grid.setSelectionMode(SelectionMode.NONE); grid.setSelectionMode(SelectionMode.NONE);
grid.setContainerDataSource(beanContainer); grid.setContainerDataSource(beanContainer);
grid.appendHeaderRow().getCell("responseStatus").setComponent(responseComboBox); grid.appendHeaderRow().getCell(RESPONSE_STATUS_COL).setComponent(responseComboBox);
grid.setColumnOrder("id", "status", "swversion", "progress", "tenant", "protocol", "responseStatus", grid.setColumnOrder(ID_COL, STATUS_COL, SWVERSION_COL, PROGRESS_COL, TENANT_COL, PROTOCOL_COL,
"nextPollCounterSec"); RESPONSE_STATUS_COL, NEXT_POLL_COUNTER_SEC_COL);
// header widths // header widths
grid.getColumn("status").setMaximumWidth(80); grid.getColumn(STATUS_COL).setMaximumWidth(80);
grid.getColumn("protocol").setMaximumWidth(180); grid.getColumn(PROTOCOL_COL).setMaximumWidth(180);
grid.getColumn("responseStatus").setMaximumWidth(240); grid.getColumn(RESPONSE_STATUS_COL).setMaximumWidth(240);
grid.getColumn("nextPollCounterSec").setMaximumWidth(210); grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).setMaximumWidth(210);
grid.getColumn("nextPollCounterSec").setHeaderCaption("Next Poll in (sec)"); grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).setHeaderCaption("Next Poll in (sec)");
grid.getColumn("swversion").setHeaderCaption("SW Version"); grid.getColumn(SWVERSION_COL).setHeaderCaption("SW Version");
grid.getColumn("responseStatus").setHeaderCaption("Response Update Status"); grid.getColumn(RESPONSE_STATUS_COL).setHeaderCaption("Response Update Status");
grid.getColumn("progress").setRenderer(new ProgressBarRenderer()); grid.getColumn(PROGRESS_COL).setRenderer(new ProgressBarRenderer());
grid.getColumn("protocol").setConverter(createProtocolConverter()); grid.getColumn(PROTOCOL_COL).setConverter(createProtocolConverter());
grid.getColumn("status").setRenderer(new HtmlRenderer(), createStatusConverter()); grid.getColumn(STATUS_COL).setRenderer(new HtmlRenderer(), createStatusConverter());
grid.removeColumn("tenant"); grid.removeColumn(TENANT_COL);
// grid combobox // grid combobox
responseComboBox.setItemIcon(ResponseStatus.SUCCESSFUL, FontAwesome.CHECK_CIRCLE); responseComboBox.setItemIcon(ResponseStatus.SUCCESSFUL, FontAwesome.CHECK_CIRCLE);
@@ -129,8 +142,8 @@ public class SimulatorView extends VerticalLayout implements View {
responseComboBox.setNullSelectionAllowed(false); responseComboBox.setNullSelectionAllowed(false);
responseComboBox.setValue(ResponseStatus.SUCCESSFUL); responseComboBox.setValue(ResponseStatus.SUCCESSFUL);
responseComboBox.addValueChangeListener(valueChangeEvent -> { responseComboBox.addValueChangeListener(valueChangeEvent -> {
beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus") beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId)
.setValue(valueChangeEvent.getProperty().getValue())); .getItemProperty(RESPONSE_STATUS_COL).setValue(valueChangeEvent.getProperty().getValue()));
}); });
// add all components // add all components
@@ -141,7 +154,7 @@ public class SimulatorView extends VerticalLayout implements View {
setExpandRatio(grid, 1.0F); setExpandRatio(grid, 1.0F);
// load beans // load beans
repository.getAll().forEach(device -> beanContainer.addBean(device)); repository.getAll().forEach(beanContainer::addBean);
} }
@Override @Override
@@ -150,21 +163,16 @@ public class SimulatorView extends VerticalLayout implements View {
eventbus.unregister(this); eventbus.unregister(this);
} }
@SuppressWarnings("unchecked")
@Subscribe @Subscribe
public void pollCounterUpdate(final NextPollCounterUpdate update) { public void pollCounterUpdate(final NextPollCounterUpdate update) {
final List<AbstractSimulatedDevice> devices = update.getDevices(); final List<AbstractSimulatedDevice> devices = update.getDevices();
this.getUI().access(new Runnable() { this.getUI().access(() -> devices.forEach(device -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
@Override if (item != null) {
public void run() { item.getItemProperty(NEXT_POLL_COUNTER_SEC_COL).setValue(device.getNextPollCounterSec());
devices.forEach(device -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("nextPollCounterSec").setValue(device.getNextPollCounterSec());
}
});
} }
}); }));
} }
/** /**
@@ -173,21 +181,19 @@ public class SimulatorView extends VerticalLayout implements View {
* @param update * @param update
* the update event posted on the event bus * the update event posted on the event bus
*/ */
@SuppressWarnings("unchecked")
@Subscribe @Subscribe
public void initUpdate(final InitUpdate update) { public void initUpdate(final InitUpdate update) {
final AbstractSimulatedDevice device = update.getDevice(); final AbstractSimulatedDevice device = update.getDevice();
this.getUI().access(new Runnable() { this.getUI().access(() -> {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
@Override if (item == null) {
public void run() { return;
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
if (item != null) {
item.getItemProperty("progress").setValue(device.getProgress());
item.getItemProperty("status").setValue(Status.PEDNING);
item.getItemProperty("swversion").setValue(device.getSwversion());
}
} }
item.getItemProperty(PROGRESS_COL).setValue(device.getProgress());
item.getItemProperty(STATUS_COL).setValue(Status.PEDNING);
item.getItemProperty(SWVERSION_COL).setValue(device.getSwversion());
}); });
} }
@@ -197,35 +203,37 @@ public class SimulatorView extends VerticalLayout implements View {
* @param update * @param update
* the update event posted on the event bus * the update event posted on the event bus
*/ */
@SuppressWarnings("unchecked")
@Subscribe @Subscribe
public void progessUpdate(final ProgressUpdate update) { public void progessUpdate(final ProgressUpdate update) {
final AbstractSimulatedDevice device = update.getDevice(); final AbstractSimulatedDevice device = update.getDevice();
this.getUI().access(new Runnable() { this.getUI().access(() -> {
@Override final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId());
public void run() { if (item != null) {
final BeanItem<AbstractSimulatedDevice> item = beanContainer.getItem(device.getId()); item.getItemProperty(PROGRESS_COL).setValue(device.getProgress());
if (item != null) { setStatusColumn(device, item);
item.getItemProperty("progress").setValue(device.getProgress());
if (device.getProgress() >= 1) {
switch (device.getResponseStatus()) {
case SUCCESSFUL:
item.getItemProperty("status").setValue(Status.FINISH);
break;
case ERROR:
item.getItemProperty("status").setValue(Status.ERROR);
break;
default:
item.getItemProperty("status").setValue(Status.UNKNWON);
}
} else {
item.getItemProperty("status").setValue(Status.PEDNING);
}
}
} }
}); });
} }
@SuppressWarnings("unchecked")
private void setStatusColumn(final AbstractSimulatedDevice device, final BeanItem<AbstractSimulatedDevice> item) {
if (device.getProgress() >= 1) {
switch (device.getUpdateStatus().getResponseStatus()) {
case SUCCESSFUL:
item.getItemProperty(STATUS_COL).setValue(Status.FINISH);
break;
case ERROR:
item.getItemProperty(STATUS_COL).setValue(Status.ERROR);
break;
default:
item.getItemProperty(STATUS_COL).setValue(Status.UNKNWON);
}
} else {
item.getItemProperty(STATUS_COL).setValue(Status.PEDNING);
}
}
private void createToolbar() { private void createToolbar() {
final Button createDevicesButton = new Button("generate..."); final Button createDevicesButton = new Button("generate...");
createDevicesButton.setIcon(FontAwesome.GEARS); createDevicesButton.setIcon(FontAwesome.GEARS);
@@ -246,18 +254,15 @@ public class SimulatorView extends VerticalLayout implements View {
} }
private void openGenerateDialog() { private void openGenerateDialog() {
UI.getCurrent().addWindow(new GenerateDialog(new GenerateDialogCallback() { UI.getCurrent().addWindow(
@Override new GenerateDialog((namePrefix, tenant, amount, pollDelay, basePollUrl, gatewayToken, protocol) -> {
public void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay, for (int index = 0; index < amount; index++) {
final URL basePollUrl, final String gatewayToken, final Protocol protocol) { final String deviceId = namePrefix + index;
for (int index = 0; index < amount; index++) { beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId,
final String deviceId = namePrefix + index; tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken)));
beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId, spSenderService.createOrUpdateThing(tenant, deviceId);
tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken))); }
spSenderService.createOrUpdateThing(tenant, deviceId); }));
}
}
}));
} }
private Converter<String, Protocol> createProtocolConverter() { private Converter<String, Protocol> createProtocolConverter() {

View File

@@ -4,16 +4,20 @@ The hawkBit example application is a standalone spring-boot application with an
We have have described several options for you to get access to the example. We have have described several options for you to get access to the example.
## Try out the example application in our hawkBit sandbox on Bluemix ## Try out the example application in our hawkBit sandbox on Bluemix
- try out Management UI https://hawkbit.eu-gb.mybluemix.net/UI - try out Management UI https://hawkbit.eu-gb.mybluemix.net/UI (username: admin, passwd: admin)
- try out Management API https://hawkbit.eu-gb.mybluemix.net/rest/v1/targets (don't forget basic auth header) - try out Management API https://hawkbit.eu-gb.mybluemix.net/rest/v1/targets (don't forget basic auth header; username: admin, passwd: admin)
- try out DDI API https://hawkbit.eu-gb.mybluemix.net/DEFAULT/controller/v1/MYTESTDEVICE - try out DDI API https://hawkbit.eu-gb.mybluemix.net/DEFAULT/controller/v1/MYTESTDEVICE (authentication disabled)
## On your own workstation ## On your own workstation
### Run ### Run
``` ```
java -jar examples/hawkbit-example-app/target/hawkbit-example-app-*-SNAPSHOT.jar java -jar examples/hawkbit-example-app/target/hawkbit-example-app-*-SNAPSHOT.jar
``` ```
_(Note: you have to add the JDBC driver also to your class path if you intend to use another database than H2.)_
Or: Or:
``` ```
run org eclipse.hawkbit.app.Start run org eclipse.hawkbit.app.Start
``` ```

View File

@@ -20,11 +20,11 @@ import com.vaadin.spring.annotation.SpringUI;
* login path. The easiest way to get an hawkBit login UI running is to extend * login path. The easiest way to get an hawkBit login UI running is to extend
* the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in * the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in
* this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}. * this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}.
*
*
*
*/ */
@SpringUI(path = HawkbitTheme.LOGIN_UI_PATH) @SpringUI(path = HawkbitTheme.LOGIN_UI_PATH)
// Exception squid:MaximumInheritanceDepth - Most of the inheritance comes from
// Vaadin.
@SuppressWarnings({ "squid:MaximumInheritanceDepth" })
public class MyLoginUI extends HawkbitLoginUI { public class MyLoginUI extends HawkbitLoginUI {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -29,6 +29,9 @@ import com.vaadin.spring.annotation.SpringUI;
*/ */
@SpringUI @SpringUI
@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET) @Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET)
// Exception squid:MaximumInheritanceDepth - Most of the inheritance comes from
// Vaadin.
@SuppressWarnings({ "squid:MaximumInheritanceDepth" })
public class MyUI extends HawkbitUI { public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -38,6 +38,8 @@ public class Start {
* @param args * @param args
* the VM arguments. * the VM arguments.
*/ */
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) { public static void main(final String[] args) {
SpringApplication.run(Start.class, args); SpringApplication.run(Start.class, args);
} }

View File

@@ -8,3 +8,9 @@
# #
vaadin.servlet.productionMode=true vaadin.servlet.productionMode=true
hawkbit.artifact.url.coap.enabled=false
hawkbit.artifact.url.http.enabled=false
hawkbit.artifact.url.https.enabled=true
hawkbit.artifact.url.https.pattern={protocol}://{hostname}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
hawkbit.artifact.url.https.hostname=hawkbit.eu-gb.mybluemix.net

View File

@@ -0,0 +1,32 @@
#
# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# This profile adds basic configurations for a MySQL DB usage.
# Keep in mind that you need the MariaDB driver in your classpath on compile.
# see https://github.com/eclipse/hawkbit/wiki/Run-hawkBit
spring.jpa.database=MYSQL
spring.datasource.url=jdbc:mysql://localhost:3306/hawkbit
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driverClassName=org.mariadb.jdbc.Driver
spring.datasource.max-active=100
spring.datasource.max-idle=10
spring.datasource.min-idle=10
spring.datasource.initial-size=10
spring.datasource.validation-query=select 1 from dual
spring.datasource.validation-interval=30000
spring.datasource.test-on-borrow=true
spring.datasource.test-on-return=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=30000
spring.datasource.min-evictable-idle-time-millis=60000
spring.datasource.max-wait=10000
spring.datasource.jmx-enabled=true

View File

@@ -7,21 +7,28 @@
# http://www.eclipse.org/legal/epl-v10.html # http://www.eclipse.org/legal/epl-v10.html
# #
# DDI authentication configuration
hawkbit.server.ddi.security.authentication.anonymous.enabled=true hawkbit.server.ddi.security.authentication.anonymous.enabled=true
hawkbit.server.ddi.security.authentication.targettoken.enabled=false hawkbit.server.ddi.security.authentication.targettoken.enabled=true
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=true
spring.profiles.active=amqp # Download URL generation config
hawkbit.artifact.url.coap.enabled=false
hawkbit.artifact.url.http.enabled=true
hawkbit.artifact.url.http.port=8080
hawkbit.artifact.url.https.enabled=false
## Vaadin configuration
vaadin.servlet.productionMode=false vaadin.servlet.productionMode=false
## Configuration for RabbitMQ integration ## Configuration for DMF/RabbitMQ integration
spring.profiles.active=amqp
spring.rabbitmq.username=guest spring.rabbitmq.username=guest
spring.rabbitmq.password=guest spring.rabbitmq.password=guest
spring.rabbitmq.virtualHost=/ spring.rabbitmq.virtualHost=/
spring.rabbitmq.host=localhost spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672 spring.rabbitmq.port=5672
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter_ttl
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver

View File

@@ -8,11 +8,14 @@
*/ */
package org.eclipse.hawkbit.artifact.repository; package org.eclipse.hawkbit.artifact.repository;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.security.DigestOutputStream; import java.security.DigestOutputStream;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@@ -122,7 +125,11 @@ public class ArtifactStore implements ArtifactRepository {
LOGGER.debug("storing file {} of content {}", filename, contentType); LOGGER.debug("storing file {} of content {}", filename, contentType);
tempFile = File.createTempFile("uploadFile", null); tempFile = File.createTempFile("uploadFile", null);
try (final FileOutputStream os = new FileOutputStream(tempFile)) { try (final FileOutputStream os = new FileOutputStream(tempFile)) {
return store(content, contentType, os, tempFile, hash); try (BufferedOutputStream bos = new BufferedOutputStream(os)) {
try (BufferedInputStream bis = new BufferedInputStream(content)) {
return store(content, contentType, bos, tempFile, hash);
}
}
} }
} catch (final IOException | MongoException e1) { } catch (final IOException | MongoException e1) {
throw new ArtifactStoreException(e1.getMessage(), e1); throw new ArtifactStoreException(e1.getMessage(), e1);
@@ -162,7 +169,7 @@ public class ArtifactStore implements ArtifactRepository {
} }
private DbArtifact store(final InputStream content, final String contentType, final FileOutputStream os, private DbArtifact store(final InputStream content, final String contentType, final OutputStream os,
final File tempFile, final DbArtifactHash hash) { final File tempFile, final DbArtifactHash hash) {
final GridFsArtifact storedArtifact; final GridFsArtifact storedArtifact;
try { try {
@@ -185,7 +192,8 @@ public class ArtifactStore implements ArtifactRepository {
throw new ArtifactStoreException(e.getMessage(), e); throw new ArtifactStoreException(e.getMessage(), e);
} }
if (hash != null && hash.getMd5() != null && !storedArtifact.getHashes().getMd5().equals(hash.getMd5())) { if (hash != null && hash.getMd5() != null
&& !storedArtifact.getHashes().getMd5().equalsIgnoreCase(hash.getMd5())) {
throw new HashNotMatchException("The given md5 hash " + hash.getMd5() throw new HashNotMatchException("The given md5 hash " + hash.getMd5()
+ " not matching the calculated md5 hash " + storedArtifact.getHashes().getMd5(), + " not matching the calculated md5 hash " + storedArtifact.getHashes().getMd5(),
HashNotMatchException.MD5); HashNotMatchException.MD5);
@@ -195,14 +203,14 @@ public class ArtifactStore implements ArtifactRepository {
} }
private static String computeSHA1Hash(final InputStream stream, final FileOutputStream os, private static String computeSHA1Hash(final InputStream stream, final OutputStream os, final String providedSHA1Sum)
final String providedSHA1Sum) throws NoSuchAlgorithmException, IOException { throws NoSuchAlgorithmException, IOException {
String sha1Hash; String sha1Hash;
// compute digest // compute digest
final MessageDigest md = MessageDigest.getInstance("SHA-1"); final MessageDigest md = MessageDigest.getInstance("SHA-1");
final DigestOutputStream dos = new DigestOutputStream(os, md); try (final DigestOutputStream dos = new DigestOutputStream(os, md)) {
ByteStreams.copy(stream, dos); ByteStreams.copy(stream, dos);
dos.close(); }
sha1Hash = BaseEncoding.base16().lowerCase().encode(md.digest()); sha1Hash = BaseEncoding.base16().lowerCase().encode(md.digest());
if (providedSHA1Sum != null && !providedSHA1Sum.equalsIgnoreCase(sha1Hash)) { if (providedSHA1Sum != null && !providedSHA1Sum.equalsIgnoreCase(sha1Hash)) {
throw new HashNotMatchException( throw new HashNotMatchException(

View File

@@ -71,6 +71,8 @@ public class MongoConfiguration extends AbstractMongoConfiguration {
@Override @Override
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
// Closed by pre-destroy
@SuppressWarnings({ "squid:S2095" })
public Mongo mongo() throws UnknownHostException { public Mongo mongo() throws UnknownHostException {
final MongoClientURI uri = new MongoClientURI(properties.getUri(), createBuilderOutOfOptions(options)); final MongoClientURI uri = new MongoClientURI(properties.getUri(), createBuilderOutOfOptions(options));

View File

@@ -42,6 +42,6 @@ hawkbit.controller.minPollingTime=00:00:30
# Configuration for RabbitMQ integration # Configuration for RabbitMQ integration
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter_ttl
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver

3
hawkbit-core/README.md Normal file
View File

@@ -0,0 +1,3 @@
# hawkBit Core
Various internal interfaces and utility classes.

View File

@@ -22,11 +22,10 @@ import org.springframework.core.io.support.ResourcePatternResolver;
* This resource bundles using specified basenames, to resource loading. This * This resource bundles using specified basenames, to resource loading. This
* MessageSource implementation supports more than 1 properties file with the * MessageSource implementation supports more than 1 properties file with the
* same name. All properties files will be merged. * same name. All properties files will be merged.
*
*
*
*/ */
public class DistributedResourceBundleMessageSource extends ReloadableResourceBundleMessageSource { public class DistributedResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {
// Exception squid:S2387 - Follows our upper case convention
@SuppressWarnings({ "squid:S2387" })
private static final Logger LOGGER = LoggerFactory.getLogger(DistributedResourceBundleMessageSource.class); private static final Logger LOGGER = LoggerFactory.getLogger(DistributedResourceBundleMessageSource.class);
private static final String PROPERTIES_SUFFIX = ".properties"; private static final String PROPERTIES_SUFFIX = ".properties";
private ResourceLoader resourceLoader; private ResourceLoader resourceLoader;

View File

@@ -13,7 +13,6 @@ package org.eclipse.hawkbit.api;
* URLs to specific artifacts. * URLs to specific artifacts.
* *
*/ */
@FunctionalInterface
public interface ArtifactUrlHandler { public interface ArtifactUrlHandler {
/** /**
@@ -34,4 +33,11 @@ public interface ArtifactUrlHandler {
*/ */
String getUrl(String controllerId, final Long softwareModuleId, final String filename, final String sha1Hash, String getUrl(String controllerId, final Long softwareModuleId, final String filename, final String sha1Hash,
final UrlProtocol protocol); final UrlProtocol protocol);
/**
* @param protocol
* to check support for
* @return <code>true</code> of the handler supports given protocol.
*/
boolean protocolSupported(UrlProtocol protocol);
} }

View File

@@ -79,6 +79,12 @@ public class ArtifactUrlHandlerProperties {
* @return the pattern to build the URL. * @return the pattern to build the URL.
*/ */
String getPattern(); String getPattern();
/**
* @return <code>true</code> if the {@link ProtocolProperties} is
* enabled.
*/
boolean isEnabled();
} }
/** /**
@@ -94,6 +100,20 @@ public class ArtifactUrlHandlerProperties {
*/ */
private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}";
/**
* Enables HTTP URI generation in DDI and DMF.
*/
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@Override @Override
public String getHostname() { public String getHostname() {
return hostname; return hostname;
@@ -144,6 +164,20 @@ public class ArtifactUrlHandlerProperties {
*/ */
private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}";
/**
* Enables HTTPS URI generation in DDI and DMF.
*/
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@Override @Override
public String getHostname() { public String getHostname() {
return hostname; return hostname;
@@ -194,6 +228,20 @@ public class ArtifactUrlHandlerProperties {
*/ */
private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}"; private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}";
/**
* Enables CoAP URI generation in DMF.
*/
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@Override @Override
public String getHostname() { public String getHostname() {
return hostname; return hostname;

View File

@@ -84,4 +84,15 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
return replaceMap; return replaceMap;
} }
@Override
public boolean protocolSupported(final UrlProtocol protocol) {
final String protocolString = protocol.name().toLowerCase();
final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString);
if (properties == null || properties.getPattern() == null) {
return false;
}
return properties.isEnabled();
}
} }

View File

@@ -39,6 +39,8 @@ public class TenantConfigurationPollingDurationValidator implements TenantConfig
} }
@Override @Override
// Exception squid:S1166 - Hide origin exception
@SuppressWarnings({ "squid:S1166" })
public void validate(final Object tenantConfigurationObject) { public void validate(final Object tenantConfigurationObject) {
TenantConfigurationValidator.super.validate(tenantConfigurationObject); TenantConfigurationValidator.super.validate(tenantConfigurationObject);
final String tenantConfigurationString = (String) tenantConfigurationObject; final String tenantConfigurationString = (String) tenantConfigurationObject;

View File

@@ -145,9 +145,11 @@ public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerR
actionStatus.setStatus(Status.DOWNLOAD); actionStatus.setStatus(Status.DOWNLOAD);
if (range != null) { if (range != null) {
actionStatus.addMessage("It is a partial download request: " + range); actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range
+ " of: " + request.getRequestURI());
} else { } else {
actionStatus.addMessage("Target downloads"); actionStatus.addMessage(
ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI());
} }
controllerManagement.addActionStatusMessage(actionStatus); controllerManagement.addActionStatusMessage(actionStatus);
return action; return action;

View File

@@ -182,9 +182,11 @@ public class DdiRootController implements DdiRootControllerRestApi {
statusMessage.setStatus(Status.DOWNLOAD); statusMessage.setStatus(Status.DOWNLOAD);
if (range != null) { if (range != null) {
statusMessage.addMessage("It is a partial download request: " + range); statusMessage.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range
+ " of: " + request.getRequestURI());
} else { } else {
statusMessage.addMessage("Controller downloads"); statusMessage.addMessage(
ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI());
} }
controllerManagement.addActionStatusMessage(statusMessage); controllerManagement.addActionStatusMessage(statusMessage);
return action; return action;
@@ -304,13 +306,13 @@ public class DdiRootController implements DdiRootControllerRestApi {
LOG.debug("Controller confirmed cancel (actionid: {}, targetid: {}) as we got {} report.", actionid, LOG.debug("Controller confirmed cancel (actionid: {}, targetid: {}) as we got {} report.", actionid,
targetid, feedback.getStatus().getExecution()); targetid, feedback.getStatus().getExecution());
actionStatus.setStatus(Status.CANCELED); actionStatus.setStatus(Status.CANCELED);
actionStatus.addMessage("Controller confirmed cancelation"); actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target confirmed cancelation.");
break; break;
case REJECTED: case REJECTED:
LOG.info("Controller reported internal error (actionid: {}, targetid: {}) as we got {} report.", actionid, LOG.info("Controller reported internal error (actionid: {}, targetid: {}) as we got {} report.", actionid,
targetid, feedback.getStatus().getExecution()); targetid, feedback.getStatus().getExecution());
actionStatus.setStatus(Status.WARNING); actionStatus.setStatus(Status.WARNING);
actionStatus.addMessage("Controller reported internal ERROR and REJECTED update."); actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target REJECTED update.");
break; break;
case CLOSED: case CLOSED:
handleClosedUpdateStatus(feedback, targetid, actionid, actionStatus); handleClosedUpdateStatus(feedback, targetid, actionid, actionStatus);
@@ -337,7 +339,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
LOG.debug("Controller reported intermediate status (actionid: {}, targetid: {}) as we got {} report.", actionid, LOG.debug("Controller reported intermediate status (actionid: {}, targetid: {}) as we got {} report.", actionid,
targetid, feedback.getStatus().getExecution()); targetid, feedback.getStatus().getExecution());
actionStatus.setStatus(Status.RUNNING); actionStatus.setStatus(Status.RUNNING);
actionStatus.addMessage("Controller reported: " + feedback.getStatus().getExecution()); actionStatus.addMessage(
ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported " + feedback.getStatus().getExecution());
} }
private static void handleClosedUpdateStatus(final DdiActionFeedback feedback, final String targetid, private static void handleClosedUpdateStatus(final DdiActionFeedback feedback, final String targetid,
@@ -346,10 +349,10 @@ public class DdiRootController implements DdiRootControllerRestApi {
feedback.getStatus().getExecution()); feedback.getStatus().getExecution());
if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) { if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) {
actionStatus.setStatus(Status.ERROR); actionStatus.setStatus(Status.ERROR);
actionStatus.addMessage("Controller reported CLOSED with ERROR!"); actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with ERROR!");
} else { } else {
actionStatus.setStatus(Status.FINISHED); actionStatus.setStatus(Status.FINISHED);
actionStatus.addMessage("Controller reported CLOSED with OK!"); actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with OK!");
} }
} }
@@ -387,8 +390,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
LOG.debug("Found an active CancelAction for target {}. returning cancel: {}", targetid, cancel); LOG.debug("Found an active CancelAction for target {}. returning cancel: {}", targetid, cancel);
controllerManagement.registerRetrieved(action, controllerManagement.registerRetrieved(action, ControllerManagement.SERVER_MESSAGE_PREFIX
"Controller retrieved cancel action and should start now the cancelation."); + "Target retrieved cancel action and should start now the cancelation.");
return new ResponseEntity<>(cancel, HttpStatus.OK); return new ResponseEntity<>(cancel, HttpStatus.OK);
} }

View File

@@ -8,9 +8,6 @@
*/ */
package org.eclipse.hawkbit.amqp; package org.eclipse.hawkbit.amqp;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings; import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.BindingBuilder;
@@ -18,6 +15,7 @@ import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue; import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
@@ -31,15 +29,31 @@ import org.springframework.context.annotation.Bean;
* {@code amqp} to use a AMQP for communication with SP enabled devices. * {@code amqp} to use a AMQP for communication with SP enabled devices.
* *
*/ */
@EnableConfigurationProperties(AmqpProperties.class) @EnableConfigurationProperties({ AmqpProperties.class, AmqpDeadletterProperties.class })
public class AmqpConfiguration { public class AmqpConfiguration {
@Autowired @Autowired
protected AmqpProperties amqpProperties; protected AmqpProperties amqpProperties;
@Autowired
protected AmqpDeadletterProperties amqpDeadletterProperties;
@Autowired @Autowired
private ConnectionFactory connectionFactory; private ConnectionFactory connectionFactory;
/**
* Create a {@link RabbitAdmin} and ignore declaration exceptions.
* {@link RabbitAdmin#setIgnoreDeclarationExceptions(boolean)}
*
* @return the bean
*/
@Bean
public RabbitAdmin rabbitAdmin() {
final RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setIgnoreDeclarationExceptions(true);
return rabbitAdmin;
}
/** /**
* Method to set the Jackson2JsonMessageConverter. * Method to set the Jackson2JsonMessageConverter.
* *
@@ -59,7 +73,8 @@ public class AmqpConfiguration {
*/ */
@Bean @Bean
public Queue receiverQueue() { public Queue receiverQueue() {
return new Queue(amqpProperties.getReceiverQueue(), true, false, false, getDeadLetterExchangeArgs()); return new Queue(amqpProperties.getReceiverQueue(), true, false, false,
amqpDeadletterProperties.getDeadLetterExchangeArgs(amqpProperties.getDeadLetterExchange()));
} }
/** /**
@@ -79,7 +94,7 @@ public class AmqpConfiguration {
*/ */
@Bean @Bean
public Queue deadLetterQueue() { public Queue deadLetterQueue() {
return new Queue(amqpProperties.getDeadLetterQueue()); return amqpDeadletterProperties.createDeadletterQueue(amqpProperties.getDeadLetterQueue());
} }
/** /**
@@ -149,10 +164,4 @@ public class AmqpConfiguration {
return containerFactory; return containerFactory;
} }
private Map<String, Object> getDeadLetterExchangeArgs() {
final Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", amqpProperties.getDeadLetterExchange());
return args;
}
} }

View File

@@ -17,7 +17,6 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.security.CoapAnonymousPreAuthenticatedFilter;
import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter; import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter;
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousDownload; import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousDownload;
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousFilter; import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousFilter;
@@ -97,7 +96,6 @@ public class AmqpControllerAuthentfication {
filterChain.add(anonymousDownloadFilter); filterChain.add(anonymousDownloadFilter);
filterChain.add(new ControllerPreAuthenticatedAnonymousFilter(ddiSecruityProperties)); filterChain.add(new ControllerPreAuthenticatedAnonymousFilter(ddiSecruityProperties));
filterChain.add(new CoapAnonymousPreAuthenticatedFilter());
} }
/** /**

View File

@@ -0,0 +1,69 @@
/**
* 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.amqp;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Bean which holds the necessary properties for configuring the AMQP deadletter
* queue.
*/
@ConfigurationProperties("hawkbit.dmf.rabbitmq.deadLetter")
public class AmqpDeadletterProperties {
/**
* Message time to live (ttl) for the deadletter queue. Default ttl is 3
* weeks.
*/
private long ttl = Duration.ofDays(21).toMillis();
/**
* Return the deadletter arguments.
*
* @param exchange
* the deadletter exchange
* @return map which holds the properties
*/
public Map<String, Object> getDeadLetterExchangeArgs(final String exchange) {
final Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", exchange);
return args;
}
/**
* Create a deadletter queue with ttl for messages
*
* @param queueName
* the deadlette queue name
* @return the deadletter queue
*/
public Queue createDeadletterQueue(final String queueName) {
return new Queue(queueName, true, false, false, getTTLArgs());
}
private Map<String, Object> getTTLArgs() {
final Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", getTtl());
return args;
}
public long getTtl() {
return ttl;
}
public void setTtl(final long ttl) {
this.ttl = ttl;
}
}

View File

@@ -82,6 +82,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
.getSoftwareModules(); .getSoftwareModules();
final DownloadAndUpdateRequest downloadAndUpdateRequest = new DownloadAndUpdateRequest(); final DownloadAndUpdateRequest downloadAndUpdateRequest = new DownloadAndUpdateRequest();
downloadAndUpdateRequest.setActionId(targetAssignDistributionSetEvent.getActionId()); downloadAndUpdateRequest.setActionId(targetAssignDistributionSetEvent.getActionId());
downloadAndUpdateRequest.setTargetSecurityToken(targetAssignDistributionSetEvent.getTargetToken());
for (final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule : modules) { for (final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule : modules) {
final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(controllerId, softwareModule); final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(controllerId, softwareModule);
@@ -154,18 +155,26 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) { private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) {
final Artifact artifact = new Artifact(); final Artifact artifact = new Artifact();
artifact.getUrls().put(Artifact.UrlProtocol.COAP, if (artifactUrlHandler.protocolSupported(UrlProtocol.COAP)) {
artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), artifact.getUrls().put(Artifact.UrlProtocol.COAP,
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP)); artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
artifact.getUrls().put(Artifact.UrlProtocol.HTTP, localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP));
artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), }
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP));
artifact.getUrls().put(Artifact.UrlProtocol.HTTPS, if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTP)) {
artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), artifact.getUrls().put(Artifact.UrlProtocol.HTTP,
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS)); artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP));
}
if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTPS)) {
artifact.getUrls().put(Artifact.UrlProtocol.HTTPS,
artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS));
}
artifact.setFilename(localArtifact.getFilename()); artifact.setFilename(localArtifact.getFilename());
artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), null)); artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), localArtifact.getMd5Hash()));
artifact.setSize(localArtifact.getSize()); artifact.setSize(localArtifact.getSize());
return artifact; return artifact;
} }

View File

@@ -305,7 +305,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
final List<SoftwareModule> softwareModuleList = controllerManagement final List<SoftwareModule> softwareModuleList = controllerManagement
.findSoftwareModulesByDistributionSet(distributionSet); .findSoftwareModulesByDistributionSet(distributionSet);
eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(),
target.getControllerId(), action.getId(), softwareModuleList, target.getTargetInfo().getAddress())); target.getControllerId(), action.getId(), softwareModuleList, target.getTargetInfo().getAddress(),
target.getSecurityToken()));
} }
@@ -336,9 +337,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
final Action action = checkActionExist(message, actionUpdateStatus); final Action action = checkActionExist(message, actionUpdateStatus);
final ActionStatus actionStatus = new ActionStatus(); final ActionStatus actionStatus = new ActionStatus();
final List<String> messageText = actionUpdateStatus.getMessage(); actionUpdateStatus.getMessage().forEach(actionStatus::addMessage);
final String messageString = String.join(", ", messageText);
actionStatus.addMessage(messageString);
actionStatus.setAction(action); actionStatus.setAction(action);
actionStatus.setOccurredAt(System.currentTimeMillis()); actionStatus.setOccurredAt(System.currentTimeMillis());

View File

@@ -21,7 +21,7 @@ public class AmqpProperties {
/** /**
* DMF API dead letter queue. * DMF API dead letter queue.
*/ */
private String deadLetterQueue = "dmf_connector_deadletter"; private String deadLetterQueue = "dmf_connector_deadletter_ttl";
/** /**
* DMF API dead letter exchange. * DMF API dead letter exchange.

View File

@@ -8,8 +8,8 @@
*/ */
package org.eclipse.hawkbit.amqp; package org.eclipse.hawkbit.amqp;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.when;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.TestDataUtil;
@@ -58,6 +59,12 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("AmqpMessage Dispatcher Service Test") @Stories("AmqpMessage Dispatcher Service Test")
public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWithMongoDB { public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWithMongoDB {
private static final String TENANT = "default";
private static final URI AMQP_URI = IpUtil.createAmqpUri("vHost", "mytest");
private static final String TEST_TOKEN = "testToken";
private AmqpMessageDispatcherService amqpMessageDispatcherService; private AmqpMessageDispatcherService amqpMessageDispatcherService;
private RabbitTemplate rabbitTemplate; private RabbitTemplate rabbitTemplate;
@@ -89,8 +96,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit
@Description("Verfies that download and install event with no software modul works") @Description("Verfies that download and install event with no software modul works")
public void testSendDownloadRequesWithEmptySoftwareModules() { public void testSendDownloadRequesWithEmptySoftwareModules() {
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
1L, "default", CONTROLLER_ID, 1l, new ArrayList<SoftwareModule>(), 1L, TENANT, CONTROLLER_ID, 1L, new ArrayList<SoftwareModule>(), AMQP_URI, TEST_TOKEN);
IpUtil.createAmqpUri("vHost", "mytest"));
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
@@ -104,7 +110,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit
final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement,
distributionSetManagement); distributionSetManagement);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
1L, "default", CONTROLLER_ID, 1l, dsA.getModules(), IpUtil.createAmqpUri("vHost", "mytest")); 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN);
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
@@ -143,7 +149,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit
Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList); Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
1L, "default", CONTROLLER_ID, 1l, dsA.getModules(), IpUtil.createAmqpUri("vHost", "mytest")); 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN);
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
@@ -154,7 +160,19 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit
if (!softwareModule.getModuleId().equals(module.getId())) { if (!softwareModule.getModuleId().equals(module.getId())) {
continue; continue;
} }
assertFalse("The software module artifacts should not be empty", softwareModule.getArtifacts().isEmpty()); assertThat(softwareModule.getArtifacts().size()).isEqualTo(module.getArtifacts().size()).isGreaterThan(0);
module.getArtifacts().forEach(dbArtifact -> {
final Optional<org.eclipse.hawkbit.dmf.json.model.Artifact> found = softwareModule.getArtifacts()
.stream().filter(dmfartifact -> dmfartifact.getFilename()
.equals(((LocalArtifact) dbArtifact).getFilename()))
.findFirst();
assertTrue("The artifact should exist in message", found.isPresent());
assertThat(found.get().getSize()).isEqualTo(dbArtifact.getSize());
assertThat(found.get().getHashes().getMd5()).isEqualTo(dbArtifact.getMd5Hash());
assertThat(found.get().getHashes().getSha1()).isEqualTo(dbArtifact.getSha1Hash());
});
} }
} }
@@ -162,7 +180,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit
@Description("Verfies that send cancel event works") @Description("Verfies that send cancel event works")
public void testSendCancelRequest() { public void testSendCancelRequest() {
final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent( final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent(
1L, "default", CONTROLLER_ID, 1l, IpUtil.createAmqpUri("vHost", "mytest")); 1L, TENANT, CONTROLLER_ID, 1L, AMQP_URI);
amqpMessageDispatcherService amqpMessageDispatcherService
.targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent); .targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent);
final Message sendMessage = createArgumentCapture(cancelTargetAssignmentDistributionSetEvent.getTargetAdress()); final Message sendMessage = createArgumentCapture(cancelTargetAssignmentDistributionSetEvent.getTargetAdress());
@@ -187,13 +205,12 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit
downloadAndUpdateRequest.getActionId(), Long.valueOf(1)); downloadAndUpdateRequest.getActionId(), Long.valueOf(1));
assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL, assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL,
sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC)); sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC));
assertEquals("Security token of target", downloadAndUpdateRequest.getTargetSecurityToken(), TEST_TOKEN);
return downloadAndUpdateRequest; return downloadAndUpdateRequest;
} }
/**
* @param sendMessage
*/
private void assertEventMessage(final Message sendMessage) { private void assertEventMessage(final Message sendMessage) {
assertNotNull("The message should not be null", sendMessage); assertNotNull("The message should not be null", sendMessage);

View File

@@ -333,20 +333,22 @@ public class AmqpMessageHandlerServiceTest {
assertThat(downloadResponse.getResponseCode()).as("Message body response code is wrong") assertThat(downloadResponse.getResponseCode()).as("Message body response code is wrong")
.isEqualTo(HttpStatus.OK.value()); .isEqualTo(HttpStatus.OK.value());
assertThat(downloadResponse.getArtifact().getSize()).as("Wrong artifact size in message body").isEqualTo(1L); assertThat(downloadResponse.getArtifact().getSize()).as("Wrong artifact size in message body").isEqualTo(1L);
assertThat(downloadResponse.getArtifact().getHashes().getSha1()).as("Wrong sha1 hash").isEqualTo("sha1");
assertThat(downloadResponse.getArtifact().getHashes().getMd5()).as("Wrong md5 hash").isEqualTo("md5");
assertThat(downloadResponse.getDownloadUrl()).as("download url is wrong") assertThat(downloadResponse.getDownloadUrl()).as("download url is wrong")
.startsWith("http://localhost/api/v1/downloadserver/downloadId/"); .startsWith("http://localhost/api/v1/downloadserver/downloadId/");
} }
@Test @Test
@Description("Tests TODO") @Description("Tests TODO")
public void lookupNextUpdateActionAfterFinished() throws IllegalArgumentException, IllegalAccessException { public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException {
// Mock // Mock
final Action action = createActionWithTarget(22L, Status.FINISHED); final Action action = createActionWithTarget(22L, Status.FINISHED);
when(controllerManagementMock.findActionWithDetails(Matchers.any())).thenReturn(action); when(controllerManagementMock.findActionWithDetails(Matchers.any())).thenReturn(action);
when(controllerManagementMock.addUpdateActionStatus(Matchers.any(), Matchers.any())).thenReturn(action); when(controllerManagementMock.addUpdateActionStatus(Matchers.any(), Matchers.any())).thenReturn(action);
// for the test the same action can be used // for the test the same action can be used
final List<Action> actionList = new ArrayList<Action>(); final List<Action> actionList = new ArrayList<>();
actionList.add(action); actionList.add(action);
when(controllerManagementMock.findActionByTargetAndActive(Matchers.any())).thenReturn(actionList); when(controllerManagementMock.findActionByTargetAndActive(Matchers.any())).thenReturn(actionList);
@@ -372,6 +374,8 @@ public class AmqpMessageHandlerServiceTest {
assertThat(targetAssignDistributionSetEvent.getControllerId()).as("event has wrong controller id") assertThat(targetAssignDistributionSetEvent.getControllerId()).as("event has wrong controller id")
.isEqualTo("target1"); .isEqualTo("target1");
assertThat(targetAssignDistributionSetEvent.getTargetToken()).as("targetoken not filled correctly")
.isEqualTo(action.getTarget().getSecurityToken());
assertThat(targetAssignDistributionSetEvent.getActionId()).as("event has wrong action id").isEqualTo(22L); assertThat(targetAssignDistributionSetEvent.getActionId()).as("event has wrong action id").isEqualTo(22L);
assertThat(targetAssignDistributionSetEvent.getSoftwareModules()).as("event has wrong sofware modules") assertThat(targetAssignDistributionSetEvent.getSoftwareModules()).as("event has wrong sofware modules")
.isEqualTo(softwareModuleList); .isEqualTo(softwareModuleList);
@@ -379,7 +383,7 @@ public class AmqpMessageHandlerServiceTest {
} }
private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status) { private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status) {
return createActionUpdateStatus(status, 2l); return createActionUpdateStatus(status, 2L);
} }
private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status, final Long id) { private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status, final Long id) {
@@ -404,15 +408,14 @@ public class AmqpMessageHandlerServiceTest {
} }
private List<SoftwareModule> createSoftwareModuleList() { private List<SoftwareModule> createSoftwareModuleList() {
final List<SoftwareModule> softwareModuleList = new ArrayList<SoftwareModule>(); final List<SoftwareModule> softwareModuleList = new ArrayList<>();
final SoftwareModule softwareModule = new SoftwareModule(); final SoftwareModule softwareModule = new SoftwareModule();
softwareModule.setId(777L); softwareModule.setId(777L);
softwareModuleList.add(softwareModule); softwareModuleList.add(softwareModule);
return softwareModuleList; return softwareModuleList;
} }
private Action createActionWithTarget(final Long targetId, final Status status) private Action createActionWithTarget(final Long targetId, final Status status) throws IllegalAccessException {
throws IllegalArgumentException, IllegalAccessException {
// is needed for the creation of targets // is needed for the creation of targets
initalizeSecurityTokenGenerator(); initalizeSecurityTokenGenerator();
@@ -427,7 +430,7 @@ public class AmqpMessageHandlerServiceTest {
return action; return action;
} }
private void initalizeSecurityTokenGenerator() throws IllegalArgumentException, IllegalAccessException { private void initalizeSecurityTokenGenerator() throws IllegalAccessException {
final SecurityTokenGeneratorHolder instance = SecurityTokenGeneratorHolder.getInstance(); final SecurityTokenGeneratorHolder instance = SecurityTokenGeneratorHolder.getInstance();
final Field[] fields = instance.getClass().getDeclaredFields(); final Field[] fields = instance.getClass().getDeclaredFields();
for (final Field field : fields) { for (final Field field : fields) {

View File

@@ -52,6 +52,8 @@ public class BaseAmqpServiceTest {
final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus();
actionUpdateStatus.setActionId(1L); actionUpdateStatus.setActionId(1L);
actionUpdateStatus.setSoftwareModuleId(2L); actionUpdateStatus.setSoftwareModuleId(2L);
actionUpdateStatus.getMessage().add("Message 1");
actionUpdateStatus.getMessage().add("Message 2");
final Message message = rabbitTemplate.getMessageConverter().toMessage(actionUpdateStatus, final Message message = rabbitTemplate.getMessageConverter().toMessage(actionUpdateStatus,
new MessageProperties()); new MessageProperties());

View File

@@ -13,10 +13,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/** /**
* JSON representation of artifact hash. * JSON representation of artifact hash.
*
*
*
*
*/ */
public class ArtifactHash { public class ArtifactHash {

View File

@@ -19,15 +19,16 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/** /**
* JSON representation of download and update request. * JSON representation of download and update request.
* *
*
*
*
*/ */
@JsonInclude(Include.NON_NULL) @JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class DownloadAndUpdateRequest { public class DownloadAndUpdateRequest {
@JsonProperty @JsonProperty
private Long actionId; private Long actionId;
@JsonProperty
private String targetSecurityToken;
@JsonProperty @JsonProperty
private final List<SoftwareModule> softwareModules = new LinkedList<>(); private final List<SoftwareModule> softwareModules = new LinkedList<>();
@@ -39,6 +40,14 @@ public class DownloadAndUpdateRequest {
this.actionId = correlator; this.actionId = correlator;
} }
public String getTargetSecurityToken() {
return targetSecurityToken;
}
public void setTargetSecurityToken(final String targetSecurityToken) {
this.targetSecurityToken = targetSecurityToken;
}
public List<SoftwareModule> getSoftwareModules() { public List<SoftwareModule> getSoftwareModules() {
return softwareModules; return softwareModules;
} }

View File

@@ -26,8 +26,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class TenantSecurityToken { public class TenantSecurityToken {
public static final String AUTHORIZATION_HEADER = "Authorization"; public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String COAP_AUTHORIZATION_HEADER = "Coap-Authorization";
public static final String COAP_TOKEN_VALUE = "CoapToken";
@JsonProperty @JsonProperty
private final String tenant; private final String tenant;

34
hawkbit-mgmt-ui/README.md Normal file
View File

@@ -0,0 +1,34 @@
# hawkBit User Interface
The hawkBit user interface is based on the Vaadin and Vaadin-Spring framework and allows to manage software updates and large scale roll-outs via a user interface.
## Debugging client-side code
### Debug using SuperDevMode
The SuperDevMode can be used to debug client side code without any browser plugin.
#### Using SuperDevMode with chrome :
- Add required maven dependencies
- Add vaadin-client-compiler dependency
- Add jetty dependencies (version : 8.1x)
- Set redirect property in the AppWidgetSet.gwt.xml module descriptor as follows
- < set-configuration-property name="devModeRedirectEnabled" value="true" />
- Create launch configuration for the SuperDevMode
- The main class to execute should be com.google.gwt.dev.codeserver.CodeServer.
- Add fully-qualified class name of widgetset (org.eclipse.hawkbit.ui.AppWidgetSet) as parameter
- Enable debug in chrome
- Chrome inspector window ▸ Click on settings icon ▸ Scripts ▸ Enable source maps option
- Run the SuperDevMode Code Server with the launch configuration created above
- Open http://localhost:8080/UI/?debug .Click on "SuperDev" button in debug console (Alternatively can directly add ?superdevmode parameter to URL)
- Widgetset is compiled and you can see the java code files loaded in 'Chrome inspector window ▸ Source tab'
#### Using SuperDevMode with Eclipse :
- Install the plugin from http://sdbg.github.io/p2
- Start the server and Super Dev Mode as mentioned above
- Create a new launch configuration in Eclipse
- Type is "Launch Chrome"
- http://localhost:8080/UI/?superdevmode
- Launch the new configuration in debug mode
- Now breakpoints in eclipse can be set

View File

@@ -17,7 +17,7 @@
<version>0.2.0-SNAPSHOT</version> <version>0.2.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>hawkbit-mgmt-ui</artifactId> <artifactId>hawkbit-mgmt-ui</artifactId>
<name>hawkBit :: Mgmt UI</name> <name>hawkBit :: UI</name>
<description>Bosch IoT Software Provisioning server web application</description> <description>Bosch IoT Software Provisioning server web application</description>
<build> <build>
<plugins> <plugins>

View File

@@ -22,6 +22,7 @@ import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent;
import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent; import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent;
import org.eclipse.hawkbit.eventbus.event.TargetTagCreatedBulkEvent; import org.eclipse.hawkbit.eventbus.event.TargetTagCreatedBulkEvent;
import org.eclipse.hawkbit.eventbus.event.TargetTagDeletedEvent; import org.eclipse.hawkbit.eventbus.event.TargetTagDeletedEvent;
import org.eclipse.hawkbit.eventbus.event.TargetTagUpdateEvent;
/** /**
* The default hawkbit event provider. * The default hawkbit event provider.
@@ -39,6 +40,7 @@ public class HawkbitEventProvider implements UIEventProvider {
SINGLE_EVENTS.add(DistributionSetTagUpdateEvent.class); SINGLE_EVENTS.add(DistributionSetTagUpdateEvent.class);
SINGLE_EVENTS.add(RolloutGroupChangeEvent.class); SINGLE_EVENTS.add(RolloutGroupChangeEvent.class);
SINGLE_EVENTS.add(RolloutChangeEvent.class); SINGLE_EVENTS.add(RolloutChangeEvent.class);
SINGLE_EVENTS.add(TargetTagUpdateEvent.class);
BULK_EVENTS.add(TargetCreatedEvent.class); BULK_EVENTS.add(TargetCreatedEvent.class);
BULK_EVENTS.add(TargetInfoUpdateEvent.class); BULK_EVENTS.add(TargetInfoUpdateEvent.class);

View File

@@ -37,6 +37,8 @@ public class UiProperties {
/** /**
* Demo user password. * Demo user password.
*/ */
// Exception squid:S2068 - Empty password
@SuppressWarnings({ "squid:S2068" })
private String password = ""; private String password = "";
public String getPassword() { public String getPassword() {
@@ -64,6 +66,7 @@ public class UiProperties {
} }
} }
/** /**
* Links to potentially other systems (e.g. support, user management, * Links to potentially other systems (e.g. support, user management,
* documentation etc.). * documentation etc.).
@@ -227,6 +230,7 @@ public class UiProperties {
} }
} }
/** /**
* Configuration of login view. * Configuration of login view.
* *

View File

@@ -16,6 +16,7 @@ import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.SoftwareManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
@@ -101,8 +102,8 @@ public class BaseSwModuleBeanQuery extends AbstractBeanQuery<ProxyBaseSoftwareMo
proxy.setVersion(bean.getVersion()); proxy.setVersion(bean.getVersion());
proxy.setVendor(bean.getVendor()); proxy.setVendor(bean.getVendor());
proxy.setDescription(bean.getDescription()); proxy.setDescription(bean.getDescription());
proxy.setCreatedByUser(HawkbitCommonUtil.getIMUser(bean.getCreatedBy())); proxy.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(bean));
proxy.setModifiedByUser(HawkbitCommonUtil.getIMUser(bean.getLastModifiedBy())); proxy.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(bean));
return proxy; return proxy;
} }

View File

@@ -234,12 +234,13 @@ public class SoftwareModuleAddUpdateWindow implements Serializable {
mainLayout.addComponent(hLayout); mainLayout.addComponent(hLayout);
mainLayout.setComponentAlignment(hLayout, Alignment.MIDDLE_LEFT); mainLayout.setComponentAlignment(hLayout, Alignment.MIDDLE_LEFT);
mainLayout.addComponents(nameTextField, versionTextField, vendorTextField, descTextArea, buttonsLayout); mainLayout.addComponents(nameTextField, versionTextField, vendorTextField, descTextArea, buttonsLayout);
/* add main layout to the window */ /* add main layout to the window */
window = SPUIComponentProvider.getWindow(i18n.get("upload.caption.add.new.swmodule"), null, window = SPUIComponentProvider.getWindow(i18n.get("upload.caption.add.new.swmodule"), null,
SPUIDefinitions.CREATE_UPDATE_WINDOW); SPUIDefinitions.CREATE_UPDATE_WINDOW);
window.setContent(mainLayout); window.setContent(mainLayout);
window.setModal(true); window.setModal(true);
nameTextField.focus();
} }
private void addDescriptionTextChangeListener() { private void addDescriptionTextChangeListener() {

View File

@@ -257,6 +257,7 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C
mainLayout = new HorizontalLayout(); mainLayout = new HorizontalLayout();
mainLayout.addComponent(fieldButtonLayout); mainLayout.addComponent(fieldButtonLayout);
setCompositionRoot(mainLayout); setCompositionRoot(mainLayout);
typeName.focus();
} }
private void addListeners() { private void addListeners() {
@@ -553,7 +554,7 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C
.findSoftwareModuleTypeByName(typeName.getValue()); .findSoftwareModuleTypeByName(typeName.getValue());
if (createOptiongroup.getValue().equals(createTypeStr)) { if (createOptiongroup.getValue().equals(createTypeStr)) {
if (!checkIsKeyDuplicate(typeKey.getValue()) && !checkIsDuplicate(existingType)) { if (!checkIsKeyDuplicate(typeKey.getValue()) && !checkIsDuplicate(existingType)) {
crateNewSWModuleType(); createNewSWModuleType();
} }
} else { } else {
@@ -610,9 +611,9 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C
/** /**
* Create new tag. * Create new tag.
*/ */
private void crateNewSWModuleType() { private void createNewSWModuleType() {
int assignNumber = 0; int assignNumber = 0;
final String colorPicked = getColorPickedSting(); final String colorPicked = getColorPickedString();
final String typeNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeName.getValue()); final String typeNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeName.getValue());
final String typeKeyValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeKey.getValue()); final String typeKeyValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeKey.getValue());
final String typeDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeDesc.getValue()); final String typeDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeDesc.getValue());
@@ -649,7 +650,7 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C
* *
* @return String of color picked value. * @return String of color picked value.
*/ */
private String getColorPickedSting() { private String getColorPickedString() {
return "rgb(" + getSelPreview().getColor().getRed() + "," + getSelPreview().getColor().getGreen() + "," return "rgb(" + getSelPreview().getColor().getRed() + "," + getSelPreview().getColor().getGreen() + ","
+ getSelPreview().getColor().getBlue() + ")"; + getSelPreview().getColor().getBlue() + ")";
} }
@@ -675,7 +676,7 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C
existingType.setDescription(null != typeDescValue ? typeDescValue : null); existingType.setDescription(null != typeDescValue ? typeDescValue : null);
existingType.setColour(getColorPickedSting()); existingType.setColour(getColorPickedString());
swTypeManagementService.updateSoftwareModuleType(existingType); swTypeManagementService.updateSoftwareModuleType(existingType);
uiNotification.displaySuccess(i18n.get("message.update.success", new Object[] { existingType.getName() })); uiNotification.displaySuccess(i18n.get("message.update.success", new Object[] { existingType.getName() }));
closeWindow(); closeWindow();

View File

@@ -37,20 +37,12 @@ import com.vaadin.ui.Upload.SucceededListener;
* {@link StreamVariable} upload variants. * {@link StreamVariable} upload variants.
* *
* The handler manages the output to the user and at the same time ensures that * The handler manages the output to the user and at the same time ensures that
* the upload does not exceed the configued max file size. * the upload does not exceed the configured max file size.
*
*
*
*
*
* *
*/ */
public class UploadHandler implements StreamVariable, Receiver, SucceededListener, FailedListener, FinishedListener, public class UploadHandler implements StreamVariable, Receiver, SucceededListener, FailedListener, FinishedListener,
ProgressListener, StartedListener { ProgressListener, StartedListener {
/**
*
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(UploadHandler.class); private static final Logger LOG = LoggerFactory.getLogger(UploadHandler.class);
@@ -108,7 +100,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
public OutputStream receiveUpload(final String fileName, final String mimeType) { public OutputStream receiveUpload(final String fileName, final String mimeType) {
this.fileName = fileName; this.fileName = fileName;
this.mimeType = mimeType; this.mimeType = mimeType;
//reset has directory flag before upload // reset has directory flag before upload
view.setHasDirectory(false); view.setHasDirectory(false);
try { try {
if (view.checkIfSoftwareModuleIsSelected()) { if (view.checkIfSoftwareModuleIsSelected()) {
@@ -343,11 +335,6 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
} }
} }
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
@@ -356,11 +343,6 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
return result; return result;
} }
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
if (this == obj) { if (this == obj) {

View File

@@ -0,0 +1,187 @@
/**
* 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.ui.common;
import java.util.Collections;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import com.vaadin.server.VaadinService;
/**
* A Utility class to user details e.g. username
*/
public final class UserDetailsFormatter {
private static final String TRIM_APPENDIX = "...";
private static final String DETAIL_SEPERATOR = ", ";
private UserDetailsFormatter() {
}
/**
* Load user details by the user name and format the user name to max 100
* characters.
*
* @see {@link UserDetailsFormatter#loadAndFormatUsername(String, int)}
*
* @param username
* the user name
* @return the formatted user name (max 100 characters) cannot be <null>
*/
public static String loadAndFormatUsername(final String username) {
return loadAndFormatUsername(username, 100);
}
/**
* Load user details by {@link BaseEntity#getCreatedBy()} and format the
* user name. Use {@link UserDetailsFormatter#loadAndFormatUsername(String)}
*
* @param baseEntity
* the entity
* @return the formatted 'created at user name' (max 100 characters) cannot
* be <null>
*/
public static String loadAndFormatCreatedBy(final BaseEntity baseEntity) {
if (baseEntity == null || baseEntity.getCreatedBy() == null) {
return StringUtils.EMPTY;
}
return loadAndFormatUsername(baseEntity.getCreatedBy());
}
/**
* Load user details by {@link BaseEntity#getLastModifiedBy()} and format
* the user name. Use
* {@link UserDetailsFormatter#loadAndFormatUsername(String)}
*
* @param baseEntity
* the entity
* @return the formatted 'last modefied by user name' (max 100 characters)
* cannot be <null>
*/
public static String loadAndFormatLastModifiedBy(final BaseEntity baseEntity) {
if (baseEntity == null || baseEntity.getLastModifiedBy() == null) {
return StringUtils.EMPTY;
}
return loadAndFormatUsername(baseEntity.getLastModifiedBy());
}
/**
* Load user details by the current session information and format the user
* name to max 12 characters. @see
* {@link UserDetailsFormatter#loadAndFormatUsername(String, int)}
*
* @return the formatted user name (max 12 characters) cannot be <null>
*/
public static String formatCurrentUsername() {
return loadAndFormatUsername(getCurrentUser().getUsername(), 5);
}
/**
* Load user details by the user name and format the user name. If the
* loaded {@link UserDetails} is not an instance of a {@link UserPrincipal},
* then just the {@link UserDetails#getUsername()} will return.
*
* If first and last name available, they will combined. Otherwise the
* {@link UserPrincipal#getLoginname()} will formatted. The formatted name
* is reduced to 100 characters.
*
* @param username
* the user name
* @param expectedNameLength
* the name size of each name part
* @return the formatted user name (max expectedNameLength characters)
* cannot be <null>
*/
public static String loadAndFormatUsername(final String username, final int expectedNameLength) {
final UserDetails userDetails = loadUserByUsername(username);
return formatUserName(expectedNameLength, userDetails);
}
private static String formatUserName(final int expectedNameLength, final UserDetails userDetails) {
if (!(userDetails instanceof UserPrincipal)) {
return userDetails.getUsername();
}
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
String firstname = StringUtils.defaultIfEmpty(userPrincipal.getFirstname(), StringUtils.EMPTY);
if (!StringUtils.isEmpty(firstname)) {
firstname += DETAIL_SEPERATOR;
}
final String firstAndLastname = firstname
+ StringUtils.defaultIfEmpty(userPrincipal.getLastname(), StringUtils.EMPTY);
final String trimmedUsername = trimAndFormatDetail(firstAndLastname, expectedNameLength);
if (StringUtils.isEmpty(trimmedUsername)) {
return trimAndFormatDetail(userPrincipal.getLoginname(), expectedNameLength);
}
return trimmedUsername;
}
/**
* Format the current tenant. The information is loaded by the current
* session information.
*
* @return the formatted user name (max 8 characters) can be <null>
*/
public static String formatCurrentTenant() {
final UserDetails userDetails = getCurrentUser();
if (!(userDetails instanceof UserPrincipal)) {
return null;
}
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
return trimAndFormatDetail(userPrincipal.getTenant(), 8);
}
private static UserDetails getCurrentUser() {
final SecurityContext context = (SecurityContext) VaadinService.getCurrentRequest().getWrappedSession()
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
return (UserDetails) context.getAuthentication().getPrincipal();
}
private static String trimAndFormatDetail(final String formatString, final int expectedDetailLength) {
final String detail = StringUtils.defaultIfEmpty(formatString, StringUtils.EMPTY);
final String trimmedDetail = StringUtils.substring(detail, 0, expectedDetailLength);
if (StringUtils.length(detail) > expectedDetailLength) {
return trimmedDetail + TRIM_APPENDIX;
}
return trimmedDetail;
}
// Exception squid:S1166 - exception has to be hidden
@SuppressWarnings({ "squid:S1166" })
private static UserDetails loadUserByUsername(final String username) {
final UserDetailsService userDetailsService = SpringContextHelper.getBean(UserDetailsService.class);
try {
final UserDetails loadUserByUsername = userDetailsService.loadUserByUsername(username);
if (loadUserByUsername == null) {
throw new UsernameNotFoundException("User not found " + username);
}
return loadUserByUsername;
} catch (final UsernameNotFoundException e) {
return new User(username, "", Collections.emptyList());
}
}
}

View File

@@ -150,20 +150,20 @@ public abstract class AbstractTableDetailsLayout<T extends NamedEntity> extends
private void buildLayout() { private void buildLayout() {
final HorizontalLayout nameEditLayout = new HorizontalLayout(); final HorizontalLayout nameEditLayout = new HorizontalLayout();
nameEditLayout.setWidth(100.0f, Unit.PERCENTAGE); nameEditLayout.setWidth(100.0F, Unit.PERCENTAGE);
nameEditLayout.addComponent(caption); nameEditLayout.addComponent(caption);
nameEditLayout.setComponentAlignment(caption, Alignment.MIDDLE_LEFT); nameEditLayout.setComponentAlignment(caption, Alignment.TOP_LEFT);
if (hasEditPermission()) { if (hasEditPermission()) {
nameEditLayout.addComponent(editButton); nameEditLayout.addComponent(editButton);
nameEditLayout.setComponentAlignment(editButton, Alignment.MIDDLE_RIGHT); nameEditLayout.setComponentAlignment(editButton, Alignment.TOP_RIGHT);
} }
nameEditLayout.setExpandRatio(caption, 1.0f); nameEditLayout.setExpandRatio(caption, 1.0F);
nameEditLayout.addStyleName(SPUIStyleDefinitions.WIDGET_TITLE); nameEditLayout.addStyleName(SPUIStyleDefinitions.WIDGET_TITLE);
addComponent(nameEditLayout); addComponent(nameEditLayout);
setComponentAlignment(nameEditLayout, Alignment.MIDDLE_CENTER); setComponentAlignment(nameEditLayout, Alignment.TOP_CENTER);
addComponent(detailsTab); addComponent(detailsTab);
setComponentAlignment(nameEditLayout, Alignment.MIDDLE_CENTER); setComponentAlignment(nameEditLayout, Alignment.TOP_CENTER);
setSizeFull(); setSizeFull();
setHeightUndefined(); setHeightUndefined();
@@ -171,9 +171,7 @@ public abstract class AbstractTableDetailsLayout<T extends NamedEntity> extends
} }
private Label createHeaderCaption() { private Label createHeaderCaption() {
final Label captionLabel = SPUIComponentProvider.getLabel(getDefaultCaption(), return SPUIComponentProvider.getLabel(getDefaultCaption(), SPUILabelDefinitions.SP_WIDGET_CAPTION);
SPUILabelDefinitions.SP_WIDGET_CAPTION);
return captionLabel;
} }
protected VerticalLayout getTabLayout() { protected VerticalLayout getTabLayout() {
@@ -213,22 +211,22 @@ public abstract class AbstractTableDetailsLayout<T extends NamedEntity> extends
populateDetailsWidget(); populateDetailsWidget();
} }
protected void updateLogLayout(final VerticalLayout changeLogLayout, final Long lastModifiedAt, protected void populateLog() {
final String lastModifiedBy, final Long createdAt, final String createdBy, final I18N i18n) { logLayout.removeAllComponents();
changeLogLayout.removeAllComponents();
changeLogLayout.addComponent(SPUIComponentProvider.createNameValueLabel(i18n.get("label.created.at"),
createdAt == null ? "" : SPDateTimeUtil.getFormattedDate(createdAt)));
changeLogLayout.addComponent(SPUIComponentProvider.createNameValueLabel(i18n.get("label.created.by"), logLayout.addComponent(SPUIComponentProvider.createNameValueLabel(i18n.get("label.created.at"),
createdBy == null ? "" : HawkbitCommonUtil.getIMUser(createdBy))); SPDateTimeUtil.formatCreatedAt(selectedBaseEntity)));
if (null != lastModifiedAt) { logLayout.addComponent(SPUIComponentProvider.createCreatedByLabel(i18n, selectedBaseEntity));
changeLogLayout.addComponent(SPUIComponentProvider.createNameValueLabel(i18n.get("label.modified.date"),
SPDateTimeUtil.getFormattedDate(lastModifiedAt)));
changeLogLayout.addComponent(SPUIComponentProvider.createNameValueLabel(i18n.get("label.modified.by"), if (selectedBaseEntity == null || selectedBaseEntity.getLastModifiedAt() == null) {
lastModifiedBy == null ? "" : HawkbitCommonUtil.getIMUser(lastModifiedBy))); return;
} }
logLayout.addComponent(SPUIComponentProvider.createNameValueLabel(i18n.get("label.modified.date"),
SPDateTimeUtil.formatLastModifiedAt(selectedBaseEntity)));
logLayout.addComponent(SPUIComponentProvider.createLastModifiedByLabel(i18n, selectedBaseEntity));
} }
protected void updateDescriptionLayout(final String descriptionLabel, final String description) { protected void updateDescriptionLayout(final String descriptionLabel, final String description) {
@@ -320,19 +318,6 @@ public abstract class AbstractTableDetailsLayout<T extends NamedEntity> extends
return detailsLayout; return detailsLayout;
} }
public VerticalLayout getLogLayout() {
return logLayout;
}
private void populateLog() {
if (selectedBaseEntity == null) {
updateLogLayout(getLogLayout(), null, StringUtils.EMPTY, null, null, i18n);
return;
}
updateLogLayout(getLogLayout(), selectedBaseEntity.getLastModifiedAt(), selectedBaseEntity.getLastModifiedBy(),
selectedBaseEntity.getCreatedAt(), selectedBaseEntity.getCreatedBy(), i18n);
}
private void populateDescription() { private void populateDescription() {
if (selectedBaseEntity != null) { if (selectedBaseEntity != null) {
updateDescriptionLayout(i18n.get("label.description"), selectedBaseEntity.getDescription()); updateDescriptionLayout(i18n.get("label.description"), selectedBaseEntity.getDescription());

View File

@@ -20,7 +20,7 @@ import javax.annotation.PreDestroy;
import org.eclipse.hawkbit.repository.model.NamedEntity; import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
import org.eclipse.hawkbit.ui.common.ManagmentEntityState; import org.eclipse.hawkbit.ui.common.ManagmentEntityState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.I18N;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
@@ -212,9 +212,9 @@ public abstract class AbstractTable<E extends NamedEntity, I> extends Table {
item.getItemProperty(SPUILabelDefinitions.VAR_ID).setValue(baseEntity.getId()); item.getItemProperty(SPUILabelDefinitions.VAR_ID).setValue(baseEntity.getId());
item.getItemProperty(SPUILabelDefinitions.VAR_DESC).setValue(baseEntity.getDescription()); item.getItemProperty(SPUILabelDefinitions.VAR_DESC).setValue(baseEntity.getDescription());
item.getItemProperty(SPUILabelDefinitions.VAR_CREATED_BY) item.getItemProperty(SPUILabelDefinitions.VAR_CREATED_BY)
.setValue(HawkbitCommonUtil.getIMUser(baseEntity.getCreatedBy())); .setValue(UserDetailsFormatter.loadAndFormatCreatedBy(baseEntity));
item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY) item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY)
.setValue(HawkbitCommonUtil.getIMUser(baseEntity.getLastModifiedBy())); .setValue(UserDetailsFormatter.loadAndFormatLastModifiedBy(baseEntity));
item.getItemProperty(SPUILabelDefinitions.VAR_CREATED_DATE) item.getItemProperty(SPUILabelDefinitions.VAR_CREATED_DATE)
.setValue(SPDateTimeUtil.getFormattedDate(baseEntity.getCreatedAt())); .setValue(SPDateTimeUtil.getFormattedDate(baseEntity.getCreatedAt()));
item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE) item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE)
@@ -329,6 +329,17 @@ public abstract class AbstractTable<E extends NamedEntity, I> extends Table {
columnList.add( columnList.add(
new TableColumn(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, i18n.get("header.modifiedDate"), 0.1F)); new TableColumn(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, i18n.get("header.modifiedDate"), 0.1F));
columnList.add(new TableColumn(SPUILabelDefinitions.VAR_DESC, i18n.get("header.description"), 0.2F)); columnList.add(new TableColumn(SPUILabelDefinitions.VAR_DESC, i18n.get("header.description"), 0.2F));
setItemDescriptionGenerator((source, itemId, propertyId) -> {
if (SPUILabelDefinitions.VAR_CREATED_BY.equals(propertyId)) {
return getItem(itemId).getItemProperty(SPUILabelDefinitions.VAR_CREATED_BY).getValue().toString();
}
if (SPUILabelDefinitions.VAR_LAST_MODIFIED_BY.equals(propertyId)) {
return getItem(itemId).getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY).getValue().toString();
}
return null;
});
return columnList; return columnList;
} }

View File

@@ -44,7 +44,7 @@ import com.vaadin.ui.VerticalLayout;
public abstract class AbstractTableHeader extends VerticalLayout { public abstract class AbstractTableHeader extends VerticalLayout {
private static final long serialVersionUID = 4881626370291837175L; private static final long serialVersionUID = 4881626370291837175L;
@Autowired @Autowired
protected I18N i18n; protected I18N i18n;
@@ -53,7 +53,6 @@ public abstract class AbstractTableHeader extends VerticalLayout {
@Autowired @Autowired
protected transient EventBus.SessionEventBus eventbus; protected transient EventBus.SessionEventBus eventbus;
private Label headerCaption; private Label headerCaption;
@@ -83,7 +82,7 @@ public abstract class AbstractTableHeader extends VerticalLayout {
restoreState(); restoreState();
eventbus.subscribe(this); eventbus.subscribe(this);
} }
@PreDestroy @PreDestroy
void destroy() { void destroy() {
eventbus.unsubscribe(this); eventbus.unsubscribe(this);
@@ -171,8 +170,8 @@ public abstract class AbstractTableHeader extends VerticalLayout {
} }
titleFilterIconsLayout.addComponent(maxMinIcon); titleFilterIconsLayout.addComponent(maxMinIcon);
titleFilterIconsLayout.setComponentAlignment(maxMinIcon, Alignment.TOP_RIGHT); titleFilterIconsLayout.setComponentAlignment(maxMinIcon, Alignment.TOP_RIGHT);
titleFilterIconsLayout.setExpandRatio(headerCaption, 0.4f); titleFilterIconsLayout.setExpandRatio(headerCaption, 0.4F);
titleFilterIconsLayout.setExpandRatio(searchField, 0.6f); titleFilterIconsLayout.setExpandRatio(searchField, 0.6F);
addComponent(titleFilterIconsLayout); addComponent(titleFilterIconsLayout);
@@ -192,10 +191,10 @@ public abstract class AbstractTableHeader extends VerticalLayout {
dropHintDropFilterLayout.addComponent(dropFilterLayout); dropHintDropFilterLayout.addComponent(dropFilterLayout);
dropHintDropFilterLayout.setComponentAlignment(dropFilterLayout, Alignment.TOP_CENTER); dropHintDropFilterLayout.setComponentAlignment(dropFilterLayout, Alignment.TOP_CENTER);
dropHintDropFilterLayout.setExpandRatio(dropFilterLayout, 1.0f); dropHintDropFilterLayout.setExpandRatio(dropFilterLayout, 1.0F);
} }
addComponent(dropHintDropFilterLayout); addComponent(dropHintDropFilterLayout);
setComponentAlignment(dropHintDropFilterLayout, Alignment.MIDDLE_CENTER); setComponentAlignment(dropHintDropFilterLayout, Alignment.TOP_CENTER);
addStyleName("bordered-layout"); addStyleName("bordered-layout");
addStyleName("no-border-bottom"); addStyleName("no-border-bottom");
} }

View File

@@ -36,6 +36,8 @@ public class ProxyTarget extends Target {
private DistributionSet installedDistributionSet; private DistributionSet installedDistributionSet;
private DistributionSet assignedDistributionSet;
private TargetIdName targetIdName; private TargetIdName targetIdName;
private String assignedDistNameVersion; private String assignedDistNameVersion;
@@ -249,6 +251,21 @@ public class ProxyTarget extends Target {
this.installedDistributionSet = installedDistributionSet; this.installedDistributionSet = installedDistributionSet;
} }
/**
* @return the assignedDistributionSet
*/
public DistributionSet getAssignedDistributionSet() {
return assignedDistributionSet;
}
/**
* @param assignedDistributionSet
* the assignedDistributionSet to set
*/
public void setAssignedDistributionSet(DistributionSet assignedDistributionSet) {
this.assignedDistributionSet = assignedDistributionSet;
}
/** /**
* @return the targetIdName * @return the targetIdName
*/ */
@@ -297,4 +314,5 @@ public class ProxyTarget extends Target {
public void setStatus(final Status status) { public void setStatus(final Status status) {
this.status = status; this.status = status;
} }
} }

View File

@@ -12,7 +12,9 @@ import java.util.Arrays;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonDecorator; import org.eclipse.hawkbit.ui.decorators.SPUIButtonDecorator;
import org.eclipse.hawkbit.ui.decorators.SPUIComboBoxDecorator; import org.eclipse.hawkbit.ui.decorators.SPUIComboBoxDecorator;
import org.eclipse.hawkbit.ui.decorators.SPUIHeaderLayoutDecorator; import org.eclipse.hawkbit.ui.decorators.SPUIHeaderLayoutDecorator;
@@ -20,6 +22,7 @@ import org.eclipse.hawkbit.ui.decorators.SPUILabelDecorator;
import org.eclipse.hawkbit.ui.decorators.SPUITextAreaDecorator; import org.eclipse.hawkbit.ui.decorators.SPUITextAreaDecorator;
import org.eclipse.hawkbit.ui.decorators.SPUITextFieldDecorator; import org.eclipse.hawkbit.ui.decorators.SPUITextFieldDecorator;
import org.eclipse.hawkbit.ui.decorators.SPUIWindowDecorator; import org.eclipse.hawkbit.ui.decorators.SPUIWindowDecorator;
import org.eclipse.hawkbit.ui.utils.I18N;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -328,6 +331,50 @@ public final class SPUIComponentProvider {
return nameValueLabel; return nameValueLabel;
} }
private static Label createUsernameLabel(final String label, final String username) {
String loadAndFormatUsername = StringUtils.EMPTY;
if (!StringUtils.isEmpty(username)) {
loadAndFormatUsername = UserDetailsFormatter.loadAndFormatUsername(username);
}
final Label nameValueLabel = new Label(getBoldHTMLText(label) + loadAndFormatUsername, ContentMode.HTML);
nameValueLabel.setSizeFull();
nameValueLabel.addStyleName(SPUIDefinitions.TEXT_STYLE);
nameValueLabel.addStyleName("label-style");
nameValueLabel.setDescription(loadAndFormatUsername);
return nameValueLabel;
}
/**
* Create label which represents the {@link BaseEntity#getCreatedBy()} by
* user name
*
* @param i18n
* the i18n
* @param baseEntity
* the entity
* @return the label
*/
public static Label createCreatedByLabel(final I18N i18n, final BaseEntity baseEntity) {
return createUsernameLabel(i18n.get("label.created.by"),
baseEntity == null ? StringUtils.EMPTY : baseEntity.getCreatedBy());
}
/**
* Create label which represents the
* {@link BaseEntity#getLastModifiedBy()()} by user name
*
* @param i18n
* the i18n
* @param baseEntity
* the entity
* @return the label
*/
public static Label createLastModifiedByLabel(final I18N i18n, final BaseEntity baseEntity) {
return createUsernameLabel(i18n.get("label.modified.by"),
baseEntity == null ? StringUtils.EMPTY : baseEntity.getLastModifiedBy());
}
/** /**
* Get Bold Text. * Get Bold Text.
* *

View File

@@ -1,29 +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.ui.customrenderers.client;
import org.eclipse.hawkbit.ui.customrenderers.renderers.LinkRenderer;
import com.vaadin.client.connectors.ButtonRendererConnector;
import com.vaadin.shared.ui.Connect;
/**
*
* A connector for {@link LinkRenderer}.
*
*/
@Connect(org.eclipse.hawkbit.ui.customrenderers.renderers.LinkRenderer.class)
public class LinkRendererConnector extends ButtonRendererConnector {
private static final long serialVersionUID = 7987417436367399331L;
@Override
public org.eclipse.hawkbit.ui.customrenderers.client.renderers.LinkRenderer getRenderer() {
return (org.eclipse.hawkbit.ui.customrenderers.client.renderers.LinkRenderer) super.getRenderer();
}
}

View File

@@ -0,0 +1,37 @@
/**
* 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.ui.customrenderers.client;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.connectors.ClickableRendererConnector;
import com.vaadin.client.renderers.ClickableRenderer.RendererClickHandler;
import com.vaadin.shared.ui.Connect;
import elemental.json.JsonObject;
/**
* A connector for {@link CustomObjectRenderer }.
*
*/
@Connect(org.eclipse.hawkbit.ui.customrenderers.renderers.RolloutRenderer.class)
public class RolloutRendererConnector extends ClickableRendererConnector<RolloutRendererData> {
private static final long serialVersionUID = 7734682321931830566L;
public org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRenderer getRenderer() {
return (org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRenderer) super.getRenderer();
}
@Override
protected HandlerRegistration addClickHandler(
RendererClickHandler<JsonObject> handler) {
return getRenderer().addClickHandler(handler);
}
}

View File

@@ -1,42 +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.ui.customrenderers.client.renderers;
import com.google.gwt.user.client.ui.Button;
import com.vaadin.client.renderers.ButtonRenderer;
import com.vaadin.client.ui.VButton;
import com.vaadin.client.widget.grid.RendererCellReference;
/**
*
* Renders link with provided text.
*
*/
public class LinkRenderer extends ButtonRenderer {
@Override
public void render(RendererCellReference cell, String text, Button button) {
button.setText(text);
applystyle(button);
// this is to allow the button to disappear, if the text is null
button.setVisible(text != null);
button.getElement().setId(new StringBuilder("link").append(".").append(text).toString());
}
private void applystyle(Button button) {
button.setStyleName(VButton.CLASSNAME);
button.addStyleName(getStyle("borderless"));
button.addStyleName(getStyle("small"));
button.addStyleName(getStyle("on-focus-no-border"));
button.addStyleName(getStyle("link"));
}
private String getStyle(final String style) {
return new StringBuilder(style).append(" ").append(VButton.CLASSNAME).append("-").append(style).toString();
}
}

View File

@@ -0,0 +1,65 @@
/**
* 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.ui.customrenderers.client.renderers;
import com.google.gwt.core.shared.GWT;
import com.vaadin.client.renderers.ClickableRenderer;
import com.vaadin.client.ui.VButton;
import com.vaadin.client.widget.grid.RendererCellReference;
/**
* Renders button with provided CustomObject.
* Used to display button with link.
*
*/
public class RolloutRenderer extends ClickableRenderer<RolloutRendererData, VButton> {
@Override
public VButton createWidget() {
VButton b = GWT.create(VButton.class);
b.addClickHandler(this);
b.setStylePrimaryName("v-nativebutton");
return b;
}
@Override
public void render(RendererCellReference cell, RolloutRendererData text, VButton button) {
final String creating = "CREATING";
button.setText(text.getName());
applystyle(button);
// this is to allow the button to disappear, if the text is null
button.setVisible(text.getName() != null);
button.getElement().setId(new StringBuilder("link").append(".").append(text.getName()).toString());
/*
* checking Rollout Status for applying button style. If Rollout status
* is not "CREATING", then the Rollout button is applying hyperlink
* style
*/
final boolean isStatusCreate = text.getStatus() != null && creating.equalsIgnoreCase(text.getStatus());
if (isStatusCreate) {
button.addStyleName(getStyle("boldhide"));
button.setEnabled(false);
} else {
button.setEnabled(true);
}
}
private void applystyle(VButton button) {
button.setStyleName(VButton.CLASSNAME);
button.addStyleName(getStyle("borderless"));
button.addStyleName(getStyle("small"));
button.addStyleName(getStyle("on-focus-no-border"));
button.addStyleName(getStyle("link"));
}
private String getStyle(final String style) {
return new StringBuilder(style).append(" ").append(VButton.CLASSNAME).append("-").append(style).toString();
}
}

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.customrenderers.client.renderers;
import java.io.Serializable;
/**
* RendererData class with Name and Status.
*
*/
public class RolloutRendererData implements Serializable {
private static final long serialVersionUID = -5018181529953620263L;
private String name;
private String status;
/**
* Initialize the RendererData.
*/
public RolloutRendererData() {
}
/**
* Initialize the RendererData.
*
* @param name
* Name of the Rollout.
* @param status
* Status of Rollout.
*/
public RolloutRendererData(String name, String status) {
super();
this.name = name;
this.status = status;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@@ -1,37 +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.ui.customrenderers.renderers;
import com.vaadin.ui.renderers.ButtonRenderer;
/**
*
* Renders link with provided text.
*
*/
public class LinkRenderer extends ButtonRenderer {
private static final long serialVersionUID = -1242995370043404892L;
/**
* Intialise link renderer.
*/
public LinkRenderer() {
super();
}
/**
* Intialise link renderer with {@link RendererClickListener}
*
* @param listener
* RendererClickListener
*/
public LinkRenderer(RendererClickListener listener) {
super(listener);
}
}

View File

@@ -0,0 +1,61 @@
/**
* 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.ui.customrenderers.renderers;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
import com.vaadin.ui.renderers.ClickableRenderer;
import elemental.json.JsonValue;
/**
* Renders button with provided CustomObject.
* Used to display button with link.
*
*/
public class RolloutRenderer extends ClickableRenderer<RolloutRendererData> {
private static final long serialVersionUID = -8754180585906263554L;
/**
* Creates a new custom object renderer.
*/
public RolloutRenderer() {
super(RolloutRendererData.class, null);
}
/**
* Initialize custom object renderer with {@link Class<CustomObject>}
*
* @param presentationType
* Class<CustomObject>
*/
public RolloutRenderer(Class<RolloutRendererData> presentationType) {
super(presentationType);
}
/**
* Creates a new custom object renderer and adds the given click listener to it.
*
* @param listener
* the click listener to register
*/
public RolloutRenderer(RendererClickListener listener) {
this();
addClickListener(listener);
}
@Override
public JsonValue encode(RolloutRendererData resource) {
return super.encode(resource, RolloutRendererData.class);
}
}

View File

@@ -284,7 +284,7 @@ public class CreateUpdateDistSetTypeLayout extends CustomComponent implements Co
mainLayout.addComponent(fieldLayout); mainLayout.addComponent(fieldLayout);
mainLayout.addComponent(twinTableLayout); mainLayout.addComponent(twinTableLayout);
colorLayout = new HorizontalLayout(); colorLayout = new HorizontalLayout();
sliderLayout = new VerticalLayout(); sliderLayout = new VerticalLayout();
final HorizontalLayout chooseColorLayout = new HorizontalLayout(); final HorizontalLayout chooseColorLayout = new HorizontalLayout();
@@ -299,6 +299,7 @@ public class CreateUpdateDistSetTypeLayout extends CustomComponent implements Co
mainWindowLayout.addComponent(colorLayout); mainWindowLayout.addComponent(colorLayout);
mainWindowLayout.addComponent(buttonLayout); mainWindowLayout.addComponent(buttonLayout);
setCompositionRoot(mainWindowLayout); setCompositionRoot(mainWindowLayout);
typeName.focus();
} }
private HorizontalLayout createTwinColumnLayout() { private HorizontalLayout createTwinColumnLayout() {

View File

@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.ProxyDistribution; import org.eclipse.hawkbit.ui.components.ProxyDistribution;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
@@ -113,8 +114,8 @@ public class ManageDistBeanQuery extends AbstractBeanQuery<ProxyDistribution> {
proxyDistribution.setCreatedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getCreatedAt())); proxyDistribution.setCreatedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getCreatedAt()));
proxyDistribution.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getLastModifiedAt())); proxyDistribution.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getLastModifiedAt()));
proxyDistribution.setDescription(distributionSet.getDescription()); proxyDistribution.setDescription(distributionSet.getDescription());
proxyDistribution.setCreatedByUser(HawkbitCommonUtil.getIMUser(distributionSet.getCreatedBy())); proxyDistribution.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(distributionSet));
proxyDistribution.setModifiedByUser(HawkbitCommonUtil.getIMUser(distributionSet.getLastModifiedBy())); proxyDistribution.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(distributionSet));
proxyDistribution.setIsComplete(distributionSet.isComplete()); proxyDistribution.setIsComplete(distributionSet.isComplete());
proxyDistributions.add(proxyDistribution); proxyDistributions.add(proxyDistribution);
} }

View File

@@ -17,6 +17,7 @@ import org.eclipse.hawkbit.repository.SoftwareManagement;
import org.eclipse.hawkbit.repository.model.CustomSoftwareModule; import org.eclipse.hawkbit.repository.model.CustomSoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
@@ -99,8 +100,8 @@ public class SwModuleBeanQuery extends AbstractBeanQuery<ProxyBaseSwModuleItem>
proxyItem.setVersion(bean.getVersion()); proxyItem.setVersion(bean.getVersion());
proxyItem.setVendor(bean.getVendor()); proxyItem.setVendor(bean.getVendor());
proxyItem.setDescription(bean.getDescription()); proxyItem.setDescription(bean.getDescription());
proxyItem.setCreatedByUser(HawkbitCommonUtil.getIMUser(bean.getCreatedBy())); proxyItem.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(bean));
proxyItem.setModifiedByUser(HawkbitCommonUtil.getIMUser(bean.getLastModifiedBy())); proxyItem.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(bean));
proxyItem.setAssigned(customSoftwareModule.isAssigned()); proxyItem.setAssigned(customSoftwareModule.isAssigned());
proxyItem.setColour(bean.getType().getColour()); proxyItem.setColour(bean.getType().getColour());
proxyItem.setTypeId(bean.getType().getId()); proxyItem.setTypeId(bean.getType().getId());

View File

@@ -68,6 +68,8 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
private static final long serialVersionUID = 7474232427119031474L; private static final long serialVersionUID = 7474232427119031474L;
private static final String breadcrumbCustomFilters = "breadcrumb.target.filter.custom.filters";
@Autowired @Autowired
private I18N i18n; private I18N i18n;
@@ -93,6 +95,12 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
@Qualifier("uiExecutor") @Qualifier("uiExecutor")
private transient Executor executor; private transient Executor executor;
private HorizontalLayout breadcrumbLayout;
private Button breadcrumbButton;
private Label breadcrumbName;
private Label headerCaption; private Label headerCaption;
private TextField queryTextField; private TextField queryTextField;
@@ -169,6 +177,7 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
oldFilterName = filterManagementUIState.getTfQuery().get().getName(); oldFilterName = filterManagementUIState.getTfQuery().get().getName();
oldFilterQuery = filterManagementUIState.getTfQuery().get().getQuery(); oldFilterQuery = filterManagementUIState.getTfQuery().get().getQuery();
} }
breadcrumbName.setValue(nameLabel.getValue());
showValidationSuccesIcon(); showValidationSuccesIcon();
titleFilterIconsLayout.addStyleName(SPUIStyleDefinitions.TARGET_FILTER_CAPTION_LAYOUT); titleFilterIconsLayout.addStyleName(SPUIStyleDefinitions.TARGET_FILTER_CAPTION_LAYOUT);
headerCaption.setVisible(false); headerCaption.setVisible(false);
@@ -177,6 +186,7 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
private void resetComponents() { private void resetComponents() {
headerCaption.setVisible(true); headerCaption.setVisible(true);
breadcrumbName.setValue(headerCaption.getValue());
nameLabel.setValue(""); nameLabel.setValue("");
queryTextField.setValue(""); queryTextField.setValue("");
setInitialStatusIconStyle(validationIcon); setInitialStatusIconStyle(validationIcon);
@@ -201,6 +211,9 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
} }
private void createComponents() { private void createComponents() {
breadcrumbButton = createBreadcrumbButton();
headerCaption = SPUIComponentProvider.getLabel(SPUILabelDefinitions.VAR_CREATE_FILTER, headerCaption = SPUIComponentProvider.getLabel(SPUILabelDefinitions.VAR_CREATE_FILTER,
SPUILabelDefinitions.SP_WIDGET_CAPTION); SPUILabelDefinitions.SP_WIDGET_CAPTION);
@@ -221,12 +234,23 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
closeIcon = createSearchResetIcon(); closeIcon = createSearchResetIcon();
} }
private Button createBreadcrumbButton() {
final Button createFilterViewLink = SPUIComponentProvider.getButton(null, "", "", null, false, null,
SPUIButtonStyleSmallNoBorder.class);
createFilterViewLink.setStyleName(ValoTheme.LINK_SMALL + " " + "on-focus-no-border link rollout-caption-links");
createFilterViewLink.setDescription(i18n.get(breadcrumbCustomFilters));
createFilterViewLink.setCaption(i18n.get(breadcrumbCustomFilters));
createFilterViewLink.addClickListener(value -> showCustomFiltersView());
return createFilterViewLink;
}
private TextField createNameTextField() { private TextField createNameTextField() {
final TextField nameField = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, false, null, final TextField nameField = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY, false, null,
i18n.get("textfield.customfiltername"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); i18n.get("textfield.customfiltername"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH);
nameField.setId(SPUIComponetIdProvider.CUSTOM_FILTER_ADD_NAME); nameField.setId(SPUIComponetIdProvider.CUSTOM_FILTER_ADD_NAME);
nameField.setPropertyDataSource(nameLabel); nameField.setPropertyDataSource(nameLabel);
nameField.addTextChangeListener(event -> onFiterNameChange(event)); nameField.addTextChangeListener(event -> onFilterNameChange(event));
return nameField; return nameField;
} }
@@ -256,7 +280,7 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
}; };
} }
private void onFiterNameChange(final TextChangeEvent event) { private void onFilterNameChange(final TextChangeEvent event) {
if (isNameAndQueryEmpty(event.getText(), queryTextField.getValue()) if (isNameAndQueryEmpty(event.getText(), queryTextField.getValue())
|| (event.getText().equals(oldFilterName) && queryTextField.getValue().equals(oldFilterQuery))) { || (event.getText().equals(oldFilterName) && queryTextField.getValue().equals(oldFilterQuery))) {
saveButton.setEnabled(false); saveButton.setEnabled(false);
@@ -276,6 +300,13 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
titleFilterIconsLayout.addComponents(headerCaption, captionLayout); titleFilterIconsLayout.addComponents(headerCaption, captionLayout);
titleFilterIconsLayout.setSpacing(true); titleFilterIconsLayout.setSpacing(true);
breadcrumbLayout = new HorizontalLayout();
breadcrumbLayout.addComponent(breadcrumbButton);
breadcrumbLayout.addComponent(new Label(">"));
breadcrumbName = SPUIComponentProvider.getLabel(null, SPUILabelDefinitions.SP_WIDGET_CAPTION);
breadcrumbLayout.addComponent(breadcrumbName);
breadcrumbName.addStyleName("breadcrumbPaddingLeft");
final HorizontalLayout titleFilterLayout = new HorizontalLayout(); final HorizontalLayout titleFilterLayout = new HorizontalLayout();
titleFilterLayout.setSizeFull(); titleFilterLayout.setSizeFull();
titleFilterLayout.addComponents(titleFilterIconsLayout, closeIcon); titleFilterLayout.addComponents(titleFilterIconsLayout, closeIcon);
@@ -290,7 +321,7 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
searchLayout.setSpacing(false); searchLayout.setSpacing(false);
searchLayout.addComponents(validationIcon, queryTextField); searchLayout.addComponents(validationIcon, queryTextField);
searchLayout.addStyleName("custom-search-layout"); searchLayout.addStyleName("custom-search-layout");
searchLayout.setComponentAlignment(validationIcon, Alignment.MIDDLE_CENTER); searchLayout.setComponentAlignment(validationIcon, Alignment.TOP_CENTER);
final HorizontalLayout iconLayout = new HorizontalLayout(); final HorizontalLayout iconLayout = new HorizontalLayout();
iconLayout.setSizeUndefined(); iconLayout.setSizeUndefined();
@@ -302,10 +333,12 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
queryLayout.setSpacing(true); queryLayout.setSpacing(true);
queryLayout.addComponents(searchLayout, iconLayout); queryLayout.addComponents(searchLayout, iconLayout);
addComponent(breadcrumbLayout);
addComponent(titleFilterLayout); addComponent(titleFilterLayout);
addComponent(queryLayout); addComponent(queryLayout);
setSpacing(true); setSpacing(true);
addStyleName(SPUIStyleDefinitions.WIDGET_TITLE); addStyleName(SPUIStyleDefinitions.WIDGET_TITLE);
addStyleName("bordered-layout");
} }
private void setUpCaptionLayout(final boolean isCreateView) { private void setUpCaptionLayout(final boolean isCreateView) {
@@ -524,4 +557,8 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button
} }
} }
private void showCustomFiltersView() {
eventBus.publish(this, CustomFilterUIEvent.SHOW_FILTER_MANAGEMENT);
}
} }

View File

@@ -17,10 +17,12 @@ import java.util.Map;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.filtermanagement.event.CustomFilterUIEvent; import org.eclipse.hawkbit.ui.filtermanagement.event.CustomFilterUIEvent;
import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState; import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState;
import org.eclipse.hawkbit.ui.utils.AssignInstalledDSTooltipGenerator;
import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.I18N;
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
@@ -69,6 +71,10 @@ public class CreateOrUpdateFilterTable extends Table {
private static final int PROPERTY_DEPT = 3; private static final int PROPERTY_DEPT = 3;
private static final String ASSIGN_DIST_SET = "assignedDistributionSet";
private static final String INSTALL_DIST_SET = "installedDistributionSet";
/** /**
* Initialize the Action History Table. * Initialize the Action History Table.
*/ */
@@ -87,6 +93,7 @@ public class CreateOrUpdateFilterTable extends Table {
setId(SPUIComponetIdProvider.CUSTOM_FILTER_TARGET_TABLE_ID); setId(SPUIComponetIdProvider.CUSTOM_FILTER_TARGET_TABLE_ID);
setSelectable(false); setSelectable(false);
eventBus.subscribe(this); eventBus.subscribe(this);
setItemDescriptionGenerator(new AssignInstalledDSTooltipGenerator());
} }
@PreDestroy @PreDestroy
@@ -160,6 +167,9 @@ public class CreateOrUpdateFilterTable extends Table {
private void setCollapsibleColumns() { private void setCollapsibleColumns() {
setColumnCollapsed(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY, true); setColumnCollapsed(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY, true);
setColumnCollapsed(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, true); setColumnCollapsed(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, true);
setColumnCollapsed(ASSIGN_DIST_SET, true);
setColumnCollapsed(INSTALL_DIST_SET, true);
} }
/** /**
@@ -172,10 +182,13 @@ public class CreateOrUpdateFilterTable extends Table {
container.addContainerProperty(SPUILabelDefinitions.VAR_CREATED_DATE, Date.class, null); container.addContainerProperty(SPUILabelDefinitions.VAR_CREATED_DATE, Date.class, null);
container.addContainerProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY, String.class, null, false, true); container.addContainerProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY, String.class, null, false, true);
container.addContainerProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, String.class, null, false, true); container.addContainerProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, String.class, null, false, true);
container.addContainerProperty(SPUILabelDefinitions.ASSIGNED_DISTRIBUTION_NAME_VER, String.class, "");
container.addContainerProperty(SPUILabelDefinitions.INSTALLED_DISTRIBUTION_NAME_VER, String.class, null);
container.addContainerProperty(SPUILabelDefinitions.VAR_TARGET_STATUS, TargetUpdateStatus.class, null); container.addContainerProperty(SPUILabelDefinitions.VAR_TARGET_STATUS, TargetUpdateStatus.class, null);
container.addContainerProperty(SPUILabelDefinitions.VAR_DESC, String.class, "", false, true); container.addContainerProperty(SPUILabelDefinitions.VAR_DESC, String.class, "", false, true);
container.addContainerProperty(ASSIGN_DIST_SET, DistributionSet.class, null, false, true);
container.addContainerProperty(INSTALL_DIST_SET, DistributionSet.class, null, false, true);
container.addContainerProperty(SPUILabelDefinitions.ASSIGNED_DISTRIBUTION_NAME_VER, String.class, "");
container.addContainerProperty(SPUILabelDefinitions.INSTALLED_DISTRIBUTION_NAME_VER, String.class, null);
} }
private List<TableColumn> getVisbleColumns() { private List<TableColumn> getVisbleColumns() {
@@ -186,12 +199,9 @@ public class CreateOrUpdateFilterTable extends Table {
columnList.add(new TableColumn(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY, i18n.get("header.modifiedBy"), 0.1F)); columnList.add(new TableColumn(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY, i18n.get("header.modifiedBy"), 0.1F));
columnList.add( columnList.add(
new TableColumn(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, i18n.get("header.modifiedDate"), 0.1F)); new TableColumn(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, i18n.get("header.modifiedDate"), 0.1F));
columnList.add(new TableColumn(SPUILabelDefinitions.ASSIGNED_DISTRIBUTION_NAME_VER,
i18n.get("header.assigned.ds"), 0.125F));
columnList.add(new TableColumn(SPUILabelDefinitions.INSTALLED_DISTRIBUTION_NAME_VER,
i18n.get("header.installed.ds"), 0.125F));
columnList.add(new TableColumn(SPUILabelDefinitions.VAR_DESC, i18n.get("header.description"), 0.1F)); columnList.add(new TableColumn(SPUILabelDefinitions.VAR_DESC, i18n.get("header.description"), 0.1F));
columnList.add(new TableColumn(SPUILabelDefinitions.STATUS_ICON, i18n.get("header.status"), 0.1F)); columnList.add(new TableColumn(SPUILabelDefinitions.STATUS_ICON, i18n.get("header.status"), 0.1F));
return columnList; return columnList;
} }
@@ -244,4 +254,5 @@ public class CreateOrUpdateFilterTable extends Table {
populateTableData(); populateTableData();
eventBus.publish(this, CustomFilterUIEvent.UPDATE_TARGET_FILTER_SEARCH_ICON); eventBus.publish(this, CustomFilterUIEvent.UPDATE_TARGET_FILTER_SEARCH_ICON);
} }
} }

View File

@@ -13,8 +13,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.ProxyTarget; import org.eclipse.hawkbit.ui.components.ProxyTarget;
import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState; import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
@@ -118,22 +118,9 @@ public class CustomTargetBeanQuery extends AbstractBeanQuery<ProxyTarget> {
prxyTarget.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(targ.getLastModifiedAt())); prxyTarget.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(targ.getLastModifiedAt()));
prxyTarget.setCreatedDate(SPDateTimeUtil.getFormattedDate(targ.getCreatedAt())); prxyTarget.setCreatedDate(SPDateTimeUtil.getFormattedDate(targ.getCreatedAt()));
prxyTarget.setCreatedAt(targ.getCreatedAt()); prxyTarget.setCreatedAt(targ.getCreatedAt());
prxyTarget.setCreatedByUser(HawkbitCommonUtil.getIMUser(targ.getCreatedBy())); prxyTarget.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(targ));
prxyTarget.setModifiedByUser(HawkbitCommonUtil.getIMUser(targ.getLastModifiedBy())); prxyTarget.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(targ));
final Target target = getTargetManagement().findTargetByControllerIDWithDetails(targ.getControllerId());
final DistributionSet installedDistributionSet = target.getTargetInfo().getInstalledDistributionSet();
prxyTarget.setInstalledDistributionSet(installedDistributionSet);
final DistributionSet assignedDistributionSet = target.getAssignedDistributionSet();
prxyTarget.setAssignedDistributionSet(assignedDistributionSet);
if (null != assignedDistributionSet) {
prxyTarget.setAssignedDistNameVersion(HawkbitCommonUtil.getFormattedNameVersion(
assignedDistributionSet.getName(), assignedDistributionSet.getVersion()));
}
if (null != installedDistributionSet) {
prxyTarget.setInstalledDistNameVersion(HawkbitCommonUtil.getFormattedNameVersion(
installedDistributionSet.getName(), installedDistributionSet.getVersion()));
}
prxyTarget.setUpdateStatus(targ.getTargetInfo().getUpdateStatus()); prxyTarget.setUpdateStatus(targ.getTargetInfo().getUpdateStatus());
prxyTarget.setLastTargetQuery(targ.getTargetInfo().getLastTargetQuery()); prxyTarget.setLastTargetQuery(targ.getTargetInfo().getLastTargetQuery());
prxyTarget.setTargetInfo(targ.getTargetInfo()); prxyTarget.setTargetInfo(targ.getTargetInfo());

View File

@@ -96,7 +96,8 @@ public class FilterManagementView extends VerticalLayout implements View {
} else if (custFilterUIEvent == CustomFilterUIEvent.CREATE_NEW_FILTER_CLICK } else if (custFilterUIEvent == CustomFilterUIEvent.CREATE_NEW_FILTER_CLICK
|| custFilterUIEvent == CustomFilterUIEvent.FILTER_TARGET_BY_QUERY) { || custFilterUIEvent == CustomFilterUIEvent.FILTER_TARGET_BY_QUERY) {
this.getUI().access(() -> viewCreateTargetFilterLayout()); this.getUI().access(() -> viewCreateTargetFilterLayout());
} else if (custFilterUIEvent == CustomFilterUIEvent.EXIT_CREATE_OR_UPDATE_FILTRER_VIEW) { } else if (custFilterUIEvent == CustomFilterUIEvent.EXIT_CREATE_OR_UPDATE_FILTRER_VIEW
|| custFilterUIEvent == CustomFilterUIEvent.SHOW_FILTER_MANAGEMENT) {
UI.getCurrent().access(() -> viewListView()); UI.getCurrent().access(() -> viewListView());
} }
} }
@@ -121,11 +122,11 @@ public class FilterManagementView extends VerticalLayout implements View {
tableHeaderLayout.setComponentAlignment(createNewFilterHeader, Alignment.TOP_CENTER); tableHeaderLayout.setComponentAlignment(createNewFilterHeader, Alignment.TOP_CENTER);
tableHeaderLayout.addComponent(createNewFilterTable); tableHeaderLayout.addComponent(createNewFilterTable);
tableHeaderLayout.setComponentAlignment(createNewFilterTable, Alignment.TOP_CENTER); tableHeaderLayout.setComponentAlignment(createNewFilterTable, Alignment.TOP_CENTER);
tableHeaderLayout.setExpandRatio(createNewFilterTable, 1.0f); tableHeaderLayout.setExpandRatio(createNewFilterTable, 1.0F);
addComponent(tableHeaderLayout); addComponent(tableHeaderLayout);
setComponentAlignment(tableHeaderLayout, Alignment.TOP_CENTER); setComponentAlignment(tableHeaderLayout, Alignment.TOP_CENTER);
setExpandRatio(tableHeaderLayout, 1.0f); setExpandRatio(tableHeaderLayout, 1.0F);
final HorizontalLayout targetsCountmessageLabelLayout = addTargetFilterMessageLabel(); final HorizontalLayout targetsCountmessageLabelLayout = addTargetFilterMessageLabel();
addComponent(targetsCountmessageLabelLayout); addComponent(targetsCountmessageLabelLayout);
@@ -135,17 +136,17 @@ public class FilterManagementView extends VerticalLayout implements View {
private void viewListView() { private void viewListView() {
removeAllComponents(); removeAllComponents();
final VerticalLayout tableHeaderLayout = new VerticalLayout(); final VerticalLayout tableListViewLayout = new VerticalLayout();
tableHeaderLayout.setSizeFull(); tableListViewLayout.setSizeFull();
tableHeaderLayout.setSpacing(false); tableListViewLayout.setSpacing(false);
tableHeaderLayout.setMargin(false); tableListViewLayout.setMargin(false);
tableHeaderLayout.setStyleName("table-layout"); tableListViewLayout.setStyleName("table-layout");
tableHeaderLayout.addComponent(targetFilterHeader); tableListViewLayout.addComponent(targetFilterHeader);
tableHeaderLayout.setComponentAlignment(targetFilterHeader, Alignment.TOP_CENTER); tableListViewLayout.setComponentAlignment(targetFilterHeader, Alignment.TOP_CENTER);
tableHeaderLayout.addComponent(targetFilterTable); tableListViewLayout.addComponent(targetFilterTable);
tableHeaderLayout.setComponentAlignment(targetFilterTable, Alignment.TOP_CENTER); tableListViewLayout.setComponentAlignment(targetFilterTable, Alignment.TOP_CENTER);
tableHeaderLayout.setExpandRatio(targetFilterTable, 1.0f); tableListViewLayout.setExpandRatio(targetFilterTable, 1.0F);
addComponent(tableHeaderLayout); addComponent(tableListViewLayout);
} }
private HorizontalLayout addTargetFilterMessageLabel() { private HorizontalLayout addTargetFilterMessageLabel() {

View File

@@ -31,10 +31,7 @@ import cz.jirutka.rsql.parser.RSQLParserException;
* *
* Validates the target filter query. * Validates the target filter query.
* *
*
*
*/ */
public final class FilterQueryValidation { public final class FilterQueryValidation {
private static final Logger LOGGER = LoggerFactory.getLogger(FilterQueryValidation.class); private static final Logger LOGGER = LoggerFactory.getLogger(FilterQueryValidation.class);
@@ -103,6 +100,9 @@ public final class FilterQueryValidation {
* @param expectedTokens * @param expectedTokens
* @return * @return
*/ */
// Exception squid:S2095 - see
// https://jira.sonarsource.com/browse/SONARJAVA-1478
@SuppressWarnings({ "squid:S2095" })
public static List<String> processExpectedTokens(final List<Integer> expectedTokens) { public static List<String> processExpectedTokens(final List<Integer> expectedTokens) {
final List<String> expectToken = new ArrayList<>(); final List<String> expectToken = new ArrayList<>();
if (expectedTokens.size() == 2 && expectedTokens.contains(9) && expectedTokens.contains(4)) { if (expectedTokens.size() == 2 && expectedTokens.contains(9) && expectedTokens.contains(4)) {

View File

@@ -14,6 +14,7 @@ import java.util.Map;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.ProxyTargetFilter; import org.eclipse.hawkbit.ui.components.ProxyTargetFilter;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
@@ -93,9 +94,9 @@ public class TargetFilterBeanQuery extends AbstractBeanQuery<ProxyTargetFilter>
proxyTarFilter.setName(tarFilterQuery.getName()); proxyTarFilter.setName(tarFilterQuery.getName());
proxyTarFilter.setId(tarFilterQuery.getId()); proxyTarFilter.setId(tarFilterQuery.getId());
proxyTarFilter.setCreatedDate(SPDateTimeUtil.getFormattedDate(tarFilterQuery.getCreatedAt())); proxyTarFilter.setCreatedDate(SPDateTimeUtil.getFormattedDate(tarFilterQuery.getCreatedAt()));
proxyTarFilter.setCreatedBy(HawkbitCommonUtil.getIMUser(tarFilterQuery.getCreatedBy())); proxyTarFilter.setCreatedBy(UserDetailsFormatter.loadAndFormatCreatedBy(tarFilterQuery));
proxyTarFilter.setModifiedDate(SPDateTimeUtil.getFormattedDate(tarFilterQuery.getLastModifiedAt())); proxyTarFilter.setModifiedDate(SPDateTimeUtil.getFormattedDate(tarFilterQuery.getLastModifiedAt()));
proxyTarFilter.setLastModifiedBy(HawkbitCommonUtil.getIMUser(tarFilterQuery.getLastModifiedBy())); proxyTarFilter.setLastModifiedBy(UserDetailsFormatter.loadAndFormatLastModifiedBy(tarFilterQuery));
proxyTarFilter.setQuery(tarFilterQuery.getQuery()); proxyTarFilter.setQuery(tarFilterQuery.getQuery());
proxyTargetFilter.add(proxyTarFilter); proxyTargetFilter.add(proxyTarFilter);
} }

View File

@@ -15,5 +15,5 @@ package org.eclipse.hawkbit.ui.filtermanagement.event;
* *
*/ */
public enum CustomFilterUIEvent { public enum CustomFilterUIEvent {
FILTER_TARGET_BY_QUERY, FILTER_BY_CUST_FILTER_TEXT, FILTER_BY_CUST_FILTER_TEXT_REMOVE, CREATE_NEW_FILTER_CLICK, EXIT_CREATE_OR_UPDATE_FILTRER_VIEW, TARGET_FILTER_DETAIL_VIEW, TARGET_DETAILS_VIEW, CREATE_TARGET_FILTER_QUERY, UPDATED_TARGET_FILTER_QUERY, UPDATE_TARGET_FILTER_SEARCH_ICON FILTER_TARGET_BY_QUERY, FILTER_BY_CUST_FILTER_TEXT, FILTER_BY_CUST_FILTER_TEXT_REMOVE, CREATE_NEW_FILTER_CLICK, EXIT_CREATE_OR_UPDATE_FILTRER_VIEW, TARGET_FILTER_DETAIL_VIEW, TARGET_DETAILS_VIEW, CREATE_TARGET_FILTER_QUERY, UPDATED_TARGET_FILTER_QUERY, UPDATE_TARGET_FILTER_SEARCH_ICON, SHOW_FILTER_MANAGEMENT
} }

View File

@@ -225,7 +225,7 @@ public class LoginView extends VerticalLayout implements View {
final String linkStyle = "v-link"; final String linkStyle = "v-link";
if (!uiProperties.getLinks().getDocumentation().getRoot().isEmpty()) { if (!uiProperties.getLinks().getDocumentation().getRoot().isEmpty()) {
final Link docuLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_DOCUMENATION, final Link docuLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_DOCUMENTATION,
i18n.get("link.documentation.name"), uiProperties.getLinks().getDocumentation().getRoot(), i18n.get("link.documentation.name"), uiProperties.getLinks().getDocumentation().getRoot(),
FontAwesome.QUESTION_CIRCLE, "_blank", linkStyle, true); FontAwesome.QUESTION_CIRCLE, "_blank", linkStyle, true);
links.addComponent(docuLink); links.addComponent(docuLink);

View File

@@ -145,11 +145,12 @@ public class DistributionAddUpdateWindowLayout extends VerticalLayout {
setSizeUndefined(); setSizeUndefined();
addComponents(madatoryLabel, distsetTypeNameComboBox, distNameTextField, distVersionTextField, descTextArea, addComponents(madatoryLabel, distsetTypeNameComboBox, distNameTextField, distVersionTextField, descTextArea,
reqMigStepCheckbox); reqMigStepCheckbox);
addComponent(buttonsLayout); addComponent(buttonsLayout);
setComponentAlignment(madatoryLabel, Alignment.MIDDLE_LEFT); setComponentAlignment(madatoryLabel, Alignment.MIDDLE_LEFT);
distNameTextField.focus();
}
}
/** /**
* Create required UI components. * Create required UI components.

View File

@@ -18,6 +18,7 @@ import org.eclipse.hawkbit.repository.DistributionSetFilter.DistributionSetFilte
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.ProxyDistribution; import org.eclipse.hawkbit.ui.components.ProxyDistribution;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
@@ -129,8 +130,8 @@ public class DistributionBeanQuery extends AbstractBeanQuery<ProxyDistribution>
proxyDistribution.setCreatedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getCreatedAt())); proxyDistribution.setCreatedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getCreatedAt()));
proxyDistribution.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getLastModifiedAt())); proxyDistribution.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getLastModifiedAt()));
proxyDistribution.setDescription(distributionSet.getDescription()); proxyDistribution.setDescription(distributionSet.getDescription());
proxyDistribution.setCreatedByUser(HawkbitCommonUtil.getIMUser(distributionSet.getCreatedBy())); proxyDistribution.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(distributionSet));
proxyDistribution.setModifiedByUser(HawkbitCommonUtil.getIMUser(distributionSet.getLastModifiedBy())); proxyDistribution.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(distributionSet));
proxyDistribution.setNameVersion( proxyDistribution.setNameVersion(
HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion())); HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion()));
proxyDistributions.add(proxyDistribution); proxyDistributions.add(proxyDistribution);

View File

@@ -43,10 +43,6 @@ import com.vaadin.ui.themes.ValoTheme;
@SpringComponent @SpringComponent
@VaadinSessionScope @VaadinSessionScope
public class CreateUpdateDistributionTagLayoutWindow extends CreateUpdateTagLayout { public class CreateUpdateDistributionTagLayoutWindow extends CreateUpdateTagLayout {
/**
*
*/
private static final long serialVersionUID = 444276149954167545L; private static final long serialVersionUID = 444276149954167545L;
@Autowired @Autowired
@@ -288,16 +284,22 @@ public class CreateUpdateDistributionTagLayoutWindow extends CreateUpdateTagLayo
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedBulkEvent event) { void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedBulkEvent event) {
populateTagNameCombo(); populateTagNameCombo();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEvent event) { void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEvent event) {
populateTagNameCombo(); populateTagNameCombo();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdateEvent event) { void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdateEvent event) {
populateTagNameCombo(); populateTagNameCombo();
} }

View File

@@ -61,16 +61,22 @@ public class DistributionTagButtons extends AbstractFilterButtons {
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedBulkEvent event) { void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedBulkEvent event) {
refreshTagTable(); refreshTagTable();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEvent event) { void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEvent event) {
refreshTagTable(); refreshTagTable();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdateEvent event) { void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdateEvent event) {
refreshTagTable(); refreshTagTable();
} }

View File

@@ -171,7 +171,7 @@ public abstract class CreateUpdateTagLayout extends CustomComponent implements C
tagName = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TAG_NAME, tagName = SPUIComponentProvider.getTextField("", ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TAG_NAME,
true, "", i18n.get("textfield.name"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH); true, "", i18n.get("textfield.name"), true, SPUILabelDefinitions.TEXT_FIELD_MAX_LENGTH);
tagName.setId(SPUIDefinitions.NEW_TARGET_TAG_NAME); tagName.setId(SPUIDefinitions.NEW_TARGET_TAG_NAME);
tagDesc = SPUIComponentProvider.getTextArea("", ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TAG_DESC, tagDesc = SPUIComponentProvider.getTextArea("", ValoTheme.TEXTFIELD_TINY + " " + SPUIDefinitions.TAG_DESC,
false, "", i18n.get("textfield.description"), SPUILabelDefinitions.TEXT_AREA_MAX_LENGTH); false, "", i18n.get("textfield.description"), SPUILabelDefinitions.TEXT_AREA_MAX_LENGTH);
@@ -237,7 +237,8 @@ public abstract class CreateUpdateTagLayout extends CustomComponent implements C
fieldLayout.addComponent(madatoryLabel); fieldLayout.addComponent(madatoryLabel);
fieldLayout.addComponent(tagName); fieldLayout.addComponent(tagName);
fieldLayout.addComponent(tagDesc); fieldLayout.addComponent(tagDesc);
final HorizontalLayout colorLabelLayout = new HorizontalLayout(); final HorizontalLayout colorLabelLayout = new HorizontalLayout();
colorLabelLayout.addComponents(colorLabel, tagColorPreviewBtn); colorLabelLayout.addComponents(colorLabel, tagColorPreviewBtn);
fieldLayout.addComponent(colorLabelLayout); fieldLayout.addComponent(colorLabelLayout);
@@ -257,8 +258,8 @@ public abstract class CreateUpdateTagLayout extends CustomComponent implements C
mainLayout = new HorizontalLayout(); mainLayout = new HorizontalLayout();
mainLayout.addComponent(fieldButtonLayout); mainLayout.addComponent(fieldButtonLayout);
setCompositionRoot(mainLayout); setCompositionRoot(mainLayout);
tagName.focus();
} }

View File

@@ -152,7 +152,7 @@ public class TargetAddUpdateWindowLayout extends CustomComponent {
madatoryLabel.setVisible(Boolean.FALSE); madatoryLabel.setVisible(Boolean.FALSE);
} }
mainLayout.addComponents(madatoryLabel, controllerIDTextField, nameTextField, descTextArea, buttonsLayout); mainLayout.addComponents(madatoryLabel, controllerIDTextField, nameTextField, descTextArea, buttonsLayout);
nameTextField.focus();
} }
private void addListeners() { private void addListeners() {

View File

@@ -19,6 +19,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.ProxyTarget; import org.eclipse.hawkbit.ui.components.ProxyTarget;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
@@ -130,8 +131,8 @@ public class TargetBeanQuery extends AbstractBeanQuery<ProxyTarget> {
prxyTarget.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(targ.getLastModifiedAt())); prxyTarget.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(targ.getLastModifiedAt()));
prxyTarget.setCreatedDate(SPDateTimeUtil.getFormattedDate(targ.getCreatedAt())); prxyTarget.setCreatedDate(SPDateTimeUtil.getFormattedDate(targ.getCreatedAt()));
prxyTarget.setCreatedAt(targ.getCreatedAt()); prxyTarget.setCreatedAt(targ.getCreatedAt());
prxyTarget.setCreatedByUser(HawkbitCommonUtil.getIMUser(targ.getCreatedBy())); prxyTarget.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(targ));
prxyTarget.setModifiedByUser(HawkbitCommonUtil.getIMUser(targ.getLastModifiedBy())); prxyTarget.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(targ));
if (pinnedDistId == null) { if (pinnedDistId == null) {
prxyTarget.setInstalledDistributionSet(null); prxyTarget.setInstalledDistributionSet(null);

View File

@@ -32,6 +32,7 @@ import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.ui.common.ManagmentEntityState; import org.eclipse.hawkbit.ui.common.ManagmentEntityState;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.common.table.AbstractTable; import org.eclipse.hawkbit.ui.common.table.AbstractTable;
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
import org.eclipse.hawkbit.ui.filter.FilterExpression; import org.eclipse.hawkbit.ui.filter.FilterExpression;
@@ -51,6 +52,7 @@ import org.eclipse.hawkbit.ui.management.event.TargetTableEvent;
import org.eclipse.hawkbit.ui.management.event.TargetTableEvent.TargetComponentEvent; import org.eclipse.hawkbit.ui.management.event.TargetTableEvent.TargetComponentEvent;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.management.state.TargetTableFilters; import org.eclipse.hawkbit.ui.management.state.TargetTableFilters;
import org.eclipse.hawkbit.ui.utils.AssignInstalledDSTooltipGenerator;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
@@ -136,6 +138,7 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> implements
addActionHandler(this); addActionHandler(this);
actionSelectAll = new ShortcutAction(i18n.get("action.target.table.selectall")); actionSelectAll = new ShortcutAction(i18n.get("action.target.table.selectall"));
actionUnSelectAll = new ShortcutAction(i18n.get("action.target.table.clear")); actionUnSelectAll = new ShortcutAction(i18n.get("action.target.table.clear"));
setItemDescriptionGenerator(new AssignInstalledDSTooltipGenerator());
} }
/** /**
@@ -329,7 +332,7 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> implements
if (!isMaximized()) { if (!isMaximized()) {
columnList.add(new TableColumn(SPUIDefinitions.TARGET_STATUS_POLL_TIME, "", 0.0F)); columnList.add(new TableColumn(SPUIDefinitions.TARGET_STATUS_POLL_TIME, "", 0.0F));
columnList.add(new TableColumn(SPUIDefinitions.TARGET_STATUS_PIN_TOGGLE_ICON, "", 0.0F)); columnList.add(new TableColumn(SPUIDefinitions.TARGET_STATUS_PIN_TOGGLE_ICON, "", 0.0F));
} }
return columnList; return columnList;
} }
@@ -739,7 +742,7 @@ public class TargetTable extends AbstractTable<Target, TargetIdName> implements
.setValue(updatedTarget.getTargetInfo().getLastTargetQuery()); .setValue(updatedTarget.getTargetInfo().getLastTargetQuery());
item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY) item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY)
.setValue(HawkbitCommonUtil.getIMUser(updatedTarget.getLastModifiedBy())); .setValue(UserDetailsFormatter.loadAndFormatLastModifiedBy(updatedTarget));
item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE) item.getItemProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE)
.setValue(SPDateTimeUtil.getFormattedDate(updatedTarget.getLastModifiedAt())); .setValue(SPDateTimeUtil.getFormattedDate(updatedTarget.getLastModifiedAt()));
item.getItemProperty(SPUILabelDefinitions.VAR_DESC).setValue(updatedTarget.getDescription()); item.getItemProperty(SPUILabelDefinitions.VAR_DESC).setValue(updatedTarget.getDescription());

View File

@@ -85,16 +85,22 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout {
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onEventTargetTagCreated(final TargetTagCreatedBulkEvent event) { void onEventTargetTagCreated(final TargetTagCreatedBulkEvent event) {
populateTagNameCombo(); populateTagNameCombo();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onEventTargetDeletedEvent(final TargetTagDeletedEvent event) { void onEventTargetDeletedEvent(final TargetTagDeletedEvent event) {
populateTagNameCombo(); populateTagNameCombo();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onEventTargetTagUpdateEvent(final TargetTagUpdateEvent event) { void onEventTargetTagUpdateEvent(final TargetTagUpdateEvent event) {
populateTagNameCombo(); populateTagNameCombo();
} }
@@ -144,7 +150,7 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout {
final TargetTag existingTag = tagManagement.findTargetTag(tagName.getValue()); final TargetTag existingTag = tagManagement.findTargetTag(tagName.getValue());
if (optiongroup.getValue().equals(createTagNw)) { if (optiongroup.getValue().equals(createTagNw)) {
if (!checkIsDuplicate(existingTag)) { if (!checkIsDuplicate(existingTag)) {
crateNewTag(); createNewTag();
} }
} else { } else {
@@ -182,8 +188,8 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout {
/** /**
* Create new tag. * Create new tag.
*/ */
private void crateNewTag() { private void createNewTag() {
final String colorPicked = getColorPickedSting(); final String colorPicked = getColorPickedString();
final String tagNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagName.getValue()); final String tagNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagName.getValue());
final String tagDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagDesc.getValue()); final String tagDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagDesc.getValue());
if (null != tagNameValue) { if (null != tagNameValue) {
@@ -214,7 +220,7 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout {
if (null != nameUpdateValue) { if (null != nameUpdateValue) {
targetObj.setName(nameUpdateValue); targetObj.setName(nameUpdateValue);
targetObj.setDescription(null != descUpdateValue ? descUpdateValue : null); targetObj.setDescription(null != descUpdateValue ? descUpdateValue : null);
targetObj.setColour(getColorPickedSting()); targetObj.setColour(getColorPickedString());
tagManagement.updateTargetTag(targetObj); tagManagement.updateTargetTag(targetObj);
uiNotification.displaySuccess(i18n.get("message.update.success", new Object[] { targetObj.getName() })); uiNotification.displaySuccess(i18n.get("message.update.success", new Object[] { targetObj.getName() }));
closeWindow(); closeWindow();
@@ -244,7 +250,7 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout {
* *
* @return String of color picked value. * @return String of color picked value.
*/ */
private String getColorPickedSting() { private String getColorPickedString() {
return "rgb(" + getSelPreview().getColor().getRed() + "," + getSelPreview().getColor().getGreen() + "," return "rgb(" + getSelPreview().getColor().getRed() + "," + getSelPreview().getColor().getGreen() + ","
+ getSelPreview().getColor().getBlue() + ")"; + getSelPreview().getColor().getBlue() + ")";
} }

View File

@@ -267,16 +267,22 @@ public class TargetTagFilterButtons extends AbstractFilterButtons {
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onEvent(final TargetTagUpdateEvent event) { void onEvent(final TargetTagUpdateEvent event) {
refreshContainer(); refreshContainer();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onEventTargetTagCreated(final TargetTagCreatedBulkEvent event) { void onEventTargetTagCreated(final TargetTagCreatedBulkEvent event) {
refreshContainer(); refreshContainer();
} }
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
// Exception squid:S1172 - event not needed
@SuppressWarnings({ "squid:S1172" })
void onEventTargetDeletedEvent(final TargetTagDeletedEvent event) { void onEventTargetDeletedEvent(final TargetTagDeletedEvent event) {
refreshContainer(); refreshContainer();
} }

View File

@@ -18,23 +18,20 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.HawkbitServerProperties; import org.eclipse.hawkbit.HawkbitServerProperties;
import org.eclipse.hawkbit.im.authentication.PermissionService; import org.eclipse.hawkbit.im.authentication.PermissionService;
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
import org.eclipse.hawkbit.ui.UiProperties; import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent; import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent;
import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.I18N;
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import com.vaadin.server.FontAwesome; import com.vaadin.server.FontAwesome;
import com.vaadin.server.Page; import com.vaadin.server.Page;
import com.vaadin.server.ThemeResource; import com.vaadin.server.ThemeResource;
import com.vaadin.server.VaadinService;
import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.spring.annotation.SpringComponent; import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.UIScope; import com.vaadin.spring.annotation.UIScope;
@@ -115,9 +112,9 @@ public final class DashboardMenu extends CustomComponent {
final VerticalLayout links = buildLinksAndVersion(); final VerticalLayout links = buildLinksAndVersion();
menus.addComponent(links); menus.addComponent(links);
menus.setComponentAlignment(links, Alignment.BOTTOM_CENTER); menus.setComponentAlignment(links, Alignment.BOTTOM_CENTER);
menus.setExpandRatio(links, 1.0f); menus.setExpandRatio(links, 1.0F);
menuContent.addComponent(menus); menuContent.addComponent(menus);
menuContent.setExpandRatio(menus, 1.0f); menuContent.setExpandRatio(menus, 1.0F);
dashboardMenuLayout.addComponent(menuContent); dashboardMenuLayout.addComponent(menuContent);
return dashboardMenuLayout; return dashboardMenuLayout;
@@ -139,7 +136,7 @@ public final class DashboardMenu extends CustomComponent {
final Label logo = new Label("<strong>" + i18n.get("menu.title") + "</strong>", ContentMode.HTML); final Label logo = new Label("<strong>" + i18n.get("menu.title") + "</strong>", ContentMode.HTML);
logo.setSizeUndefined(); logo.setSizeUndefined();
final HorizontalLayout logoWrapper = new HorizontalLayout(logo); final HorizontalLayout logoWrapper = new HorizontalLayout(logo);
logoWrapper.setComponentAlignment(logo, Alignment.MIDDLE_CENTER); logoWrapper.setComponentAlignment(logo, Alignment.TOP_CENTER);
logoWrapper.addStyleName("valo-menu-title"); logoWrapper.addStyleName("valo-menu-title");
return logoWrapper; return logoWrapper;
} }
@@ -151,7 +148,7 @@ public final class DashboardMenu extends CustomComponent {
final String linkStyle = "v-link"; final String linkStyle = "v-link";
if (!uiProperties.getLinks().getDocumentation().getRoot().isEmpty()) { if (!uiProperties.getLinks().getDocumentation().getRoot().isEmpty()) {
final Link docuLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_DOCUMENATION, final Link docuLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_DOCUMENTATION,
i18n.get("link.documentation.name"), uiProperties.getLinks().getDocumentation().getRoot(), i18n.get("link.documentation.name"), uiProperties.getLinks().getDocumentation().getRoot(),
FontAwesome.QUESTION_CIRCLE, "_blank", linkStyle, true); FontAwesome.QUESTION_CIRCLE, "_blank", linkStyle, true);
docuLink.setDescription(i18n.get("link.documentation.name")); docuLink.setDescription(i18n.get("link.documentation.name"));
@@ -189,63 +186,27 @@ public final class DashboardMenu extends CustomComponent {
return links; return links;
} }
private UserDetails getCurrentUser() {
final SecurityContext context = (SecurityContext) VaadinService.getCurrentRequest().getWrappedSession()
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
return (UserDetails) context.getAuthentication().getPrincipal();
}
private Component buildUserMenu() { private Component buildUserMenu() {
final MenuBar settings = new MenuBar(); final MenuBar settings = new MenuBar();
settings.addStyleName("user-menu"); settings.addStyleName("user-menu");
final UserDetails user = getCurrentUser(); settings.setHtmlContentAllowed(true);
final MenuItem settingsItem = settings.addItem("", new ThemeResource("images/profile-pic-57px.jpg"), null); final MenuItem settingsItem = settings.addItem("", new ThemeResource("images/profile-pic-57px.jpg"), null);
if (user instanceof UserPrincipal
&& (((UserPrincipal) user).getFirstname() != null || ((UserPrincipal) user).getLastname() != null)) { final String formattedTenant = UserDetailsFormatter.formatCurrentTenant();
settingsItem.setText(trimTanent(((UserPrincipal) user).getTenant()) + "\n" final String formattedUsername = UserDetailsFormatter.formatCurrentUsername();
+ concateFNameLName(((UserPrincipal) user).getFirstname(), ((UserPrincipal) user).getLastname())); String tenantAndUsernameHtml = "";
settingsItem.setDescription( if (!StringUtils.isEmpty(formattedTenant)) {
((UserPrincipal) user).getFirstname() + " / " + ((UserPrincipal) user).getLastname()); tenantAndUsernameHtml += formattedTenant + "<br>";
} else if (user instanceof UserPrincipal) {
if (((UserPrincipal) user).getLoginname().length() > 10) {
settingsItem.setText(trimTanent(((UserPrincipal) user).getTenant()) + "\n"
+ ((UserPrincipal) user).getLoginname().substring(0, 10) + "..");
} else {
settingsItem.setText(
trimTanent(((UserPrincipal) user).getTenant()) + "\n" + ((UserPrincipal) user).getLoginname());
}
settingsItem.setDescription(((UserPrincipal) user).getLoginname());
} else if (user != null) {
settingsItem.setText(user.getUsername());
settingsItem.setDescription(user.getUsername());
} }
tenantAndUsernameHtml += formattedUsername;
settingsItem.setText(tenantAndUsernameHtml);
settingsItem.setDescription(formattedUsername);
settingsItem.setStyleName("user-menuitem");
settingsItem.addItem("Sign Out", selectedItem -> Page.getCurrent().setLocation("/UI/logout")); settingsItem.addItem("Sign Out", selectedItem -> Page.getCurrent().setLocation("/UI/logout"));
return settings; return settings;
} }
private String concateFNameLName(final String fName, final String lName) {
final StringBuilder userName = new StringBuilder();
if (fName != null && fName.length() > 6) {
userName.append(fName.substring(0, 6) + ".." + ", ");
} else {
userName.append(fName).append(", ");
}
if (lName != null && lName.length() > 6) {
userName.append(lName.substring(0, 6) + "..");
} else {
userName.append(lName);
}
return userName.toString();
}
private String trimTanent(final String tanent) {
if (tanent != null && tanent.length() > 8) {
return tanent.substring(0, 8) + "..";
}
return tanent;
}
private Component buildToggleButton() { private Component buildToggleButton() {
final Button valoMenuToggleButton = new Button("Menu", (ClickListener) event -> { final Button valoMenuToggleButton = new Button("Menu", (ClickListener) event -> {
if (getCompositionRoot().getStyleName().contains(STYLE_VISIBLE)) { if (getCompositionRoot().getStyleName().contains(STYLE_VISIBLE)) {
@@ -264,7 +225,7 @@ public final class DashboardMenu extends CustomComponent {
private VerticalLayout buildMenuItems() { private VerticalLayout buildMenuItems() {
final VerticalLayout menuItemsLayout = new VerticalLayout(); final VerticalLayout menuItemsLayout = new VerticalLayout();
menuItemsLayout.addStyleName("valo-menuitems"); menuItemsLayout.addStyleName("valo-menuitems");
menuItemsLayout.setHeight(100.0f, Unit.PERCENTAGE); menuItemsLayout.setHeight(100.0F, Unit.PERCENTAGE);
final List<DashboardMenuItem> accessibleViews = getAccessibleViews(); final List<DashboardMenuItem> accessibleViews = getAccessibleViews();
if (accessibleViews.isEmpty()) { if (accessibleViews.isEmpty()) {

View File

@@ -209,6 +209,7 @@ public class AddUpdateRolloutWindowLayout extends CustomComponent {
actionTypeOptionGroupLayout, linkToHelp, getSaveDiscardButtonLayout()); actionTypeOptionGroupLayout, linkToHelp, getSaveDiscardButtonLayout());
mainLayout.setComponentAlignment(linkToHelp, Alignment.BOTTOM_RIGHT); mainLayout.setComponentAlignment(linkToHelp, Alignment.BOTTOM_RIGHT);
setCompositionRoot(mainLayout); setCompositionRoot(mainLayout);
rolloutName.focus();
} }
private HorizontalLayout getGroupDetailsLayout() { private HorizontalLayout getGroupDetailsLayout() {

View File

@@ -18,6 +18,7 @@ import org.eclipse.hawkbit.repository.DistributionSetFilter;
import org.eclipse.hawkbit.repository.DistributionSetFilter.DistributionSetFilterBuilder; import org.eclipse.hawkbit.repository.DistributionSetFilter.DistributionSetFilterBuilder;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.ProxyDistribution; import org.eclipse.hawkbit.ui.components.ProxyDistribution;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
@@ -62,7 +63,8 @@ public class DistributionBeanQuery extends AbstractBeanQuery<ProxyDistribution>
sort = new Sort(sortStates[0] ? Direction.ASC : Direction.DESC, (String) sortPropertyIds[0]); sort = new Sort(sortStates[0] ? Direction.ASC : Direction.DESC, (String) sortPropertyIds[0]);
// Add sort // Add sort
for (int distId = 1; distId < sortPropertyIds.length; distId++) { for (int distId = 1; distId < sortPropertyIds.length; distId++) {
sort.and(new Sort(sortStates[distId] ? Direction.ASC : Direction.DESC, (String) sortPropertyIds[distId])); sort.and(new Sort(sortStates[distId] ? Direction.ASC : Direction.DESC,
(String) sortPropertyIds[distId]));
} }
} }
} }
@@ -103,8 +105,8 @@ public class DistributionBeanQuery extends AbstractBeanQuery<ProxyDistribution>
final List<ProxyDistribution> proxyDistributions = new ArrayList<>(); final List<ProxyDistribution> proxyDistributions = new ArrayList<>();
for (final DistributionSet distributionSet : distBeans) { for (final DistributionSet distributionSet : distBeans) {
final ProxyDistribution proxyDistribution = new ProxyDistribution(); final ProxyDistribution proxyDistribution = new ProxyDistribution();
proxyDistribution.setName(HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), proxyDistribution.setName(
distributionSet.getVersion())); HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion()));
proxyDistribution.setDescription(distributionSet.getDescription()); proxyDistribution.setDescription(distributionSet.getDescription());
proxyDistribution.setDistId(distributionSet.getId()); proxyDistribution.setDistId(distributionSet.getId());
proxyDistribution.setId(distributionSet.getId()); proxyDistribution.setId(distributionSet.getId());
@@ -112,8 +114,8 @@ public class DistributionBeanQuery extends AbstractBeanQuery<ProxyDistribution>
proxyDistribution.setCreatedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getCreatedAt())); proxyDistribution.setCreatedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getCreatedAt()));
proxyDistribution.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getLastModifiedAt())); proxyDistribution.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(distributionSet.getLastModifiedAt()));
proxyDistribution.setDescription(distributionSet.getDescription()); proxyDistribution.setDescription(distributionSet.getDescription());
proxyDistribution.setCreatedByUser(HawkbitCommonUtil.getIMUser(distributionSet.getCreatedBy())); proxyDistribution.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(distributionSet));
proxyDistribution.setModifiedByUser(HawkbitCommonUtil.getIMUser(distributionSet.getLastModifiedBy())); proxyDistribution.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(distributionSet));
proxyDistribution.setIsComplete(distributionSet.isComplete()); proxyDistribution.setIsComplete(distributionSet.isComplete());
proxyDistributions.add(proxyDistribution); proxyDistributions.add(proxyDistribution);
} }

View File

@@ -8,12 +8,16 @@
*/ */
package org.eclipse.hawkbit.ui.rollout.rollout; package org.eclipse.hawkbit.ui.rollout.rollout;
import java.util.Set;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
import com.vaadin.server.FontAwesome; import com.vaadin.server.FontAwesome;
/** /**
* Proxy rollout with suctome properties. * Proxy rollout with custom properties.
* *
*/ */
public class ProxyRollout extends Rollout { public class ProxyRollout extends Rollout {
@@ -30,8 +34,92 @@ public class ProxyRollout extends Rollout {
private Boolean isActionRecieved = Boolean.FALSE; private Boolean isActionRecieved = Boolean.FALSE;
private Boolean isRequiredMigrationStep = Boolean.FALSE;
private String totalTargetsCount; private String totalTargetsCount;
private RolloutRendererData rolloutRendererData;
private String discription;
private String type;
private Set<SoftwareModule> swModules;
/**
* @return the isRequiredMigrationStep
*/
public Boolean getIsRequiredMigrationStep() {
return isRequiredMigrationStep;
}
/**
* @param isRequiredMigrationStep
* the isRequiredMigrationStep to set
*/
public void setIsRequiredMigrationStep(Boolean isRequiredMigrationStep) {
this.isRequiredMigrationStep = isRequiredMigrationStep;
}
/**
* @return the discription
*/
public String getDiscription() {
return discription;
}
/**
* @param discription
* the discription to set
*/
public void setDiscription(String discription) {
this.discription = discription;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type
* the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
*
* @return the Set of Software modules
*/
public Set<SoftwareModule> getSwModules() {
return swModules;
}
/**
* @param swModules
* Set<SoftwareModule> to set
*/
public void setSwModules(Set<SoftwareModule> swModules) {
this.swModules = swModules;
}
public RolloutRendererData getRolloutRendererData() {
return rolloutRendererData;
}
public void setRolloutRendererData(RolloutRendererData rendererData) {
this.rolloutRendererData = rendererData;
}
/** /**
* @return the distributionSetNameVersion * @return the distributionSetNameVersion
*/ */
@@ -121,10 +209,9 @@ public class ProxyRollout extends Rollout {
public void setTotalTargetsCount(final String totalTargetsCount) { public void setTotalTargetsCount(final String totalTargetsCount) {
this.totalTargetsCount = totalTargetsCount; this.totalTargetsCount = totalTargetsCount;
} }
public String getAction() {
public String getAction() {
return FontAwesome.CIRCLE_O.getHtml(); return FontAwesome.CIRCLE_O.getHtml();
} }
} }

View File

@@ -17,6 +17,8 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState; import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
@@ -119,22 +121,29 @@ public class RolloutBeanQuery extends AbstractBeanQuery<ProxyRollout> {
proxyRollout.setName(rollout.getName()); proxyRollout.setName(rollout.getName());
proxyRollout.setDescription(rollout.getDescription()); proxyRollout.setDescription(rollout.getDescription());
final DistributionSet distributionSet = rollout.getDistributionSet(); final DistributionSet distributionSet = rollout.getDistributionSet();
proxyRollout.setDistributionSetNameVersion(HawkbitCommonUtil.getFormattedNameVersion( proxyRollout.setDistributionSetNameVersion(
distributionSet.getName(), distributionSet.getVersion())); HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion()));
proxyRollout.setDistributionSet(distributionSet); proxyRollout.setDistributionSet(distributionSet);
proxyRollout.setNumberOfGroups(Long.valueOf(rollout.getRolloutGroups().size())); proxyRollout.setNumberOfGroups(Long.valueOf(rollout.getRolloutGroups().size()));
proxyRollout.setCreatedDate(SPDateTimeUtil.getFormattedDate(rollout.getCreatedAt())); proxyRollout.setCreatedDate(SPDateTimeUtil.getFormattedDate(rollout.getCreatedAt()));
proxyRollout.setModifiedDate(SPDateTimeUtil.getFormattedDate(rollout.getLastModifiedAt())); proxyRollout.setModifiedDate(SPDateTimeUtil.getFormattedDate(rollout.getLastModifiedAt()));
proxyRollout.setCreatedBy(HawkbitCommonUtil.getIMUser(rollout.getCreatedBy())); proxyRollout.setCreatedBy(UserDetailsFormatter.loadAndFormatCreatedBy(rollout));
proxyRollout.setLastModifiedBy(HawkbitCommonUtil.getIMUser(rollout.getLastModifiedBy())); proxyRollout.setLastModifiedBy(UserDetailsFormatter.loadAndFormatLastModifiedBy(rollout));
proxyRollout.setForcedTime(rollout.getForcedTime()); proxyRollout.setForcedTime(rollout.getForcedTime());
proxyRollout.setId(rollout.getId()); proxyRollout.setId(rollout.getId());
proxyRollout.setStatus(rollout.getStatus()); proxyRollout.setStatus(rollout.getStatus());
proxyRollout
.setRolloutRendererData(new RolloutRendererData(rollout.getName(), rollout.getStatus().toString()));
final TotalTargetCountStatus totalTargetCountActionStatus = rollout.getTotalTargetCountStatus(); final TotalTargetCountStatus totalTargetCountActionStatus = rollout.getTotalTargetCountStatus();
proxyRollout.setTotalTargetCountStatus(totalTargetCountActionStatus); proxyRollout.setTotalTargetCountStatus(totalTargetCountActionStatus);
proxyRollout.setTotalTargetsCount(String.valueOf(rollout.getTotalTargets())); proxyRollout.setTotalTargetsCount(String.valueOf(rollout.getTotalTargets()));
proxyRollout.setDescription(distributionSet.getDescription());
proxyRollout.setType(distributionSet.getType().getName());
proxyRollout.setIsRequiredMigrationStep(distributionSet.isRequiredMigrationStep());
proxyRollout.setSwModules(distributionSet.getModules());
proxyRolloutList.add(proxyRollout); proxyRolloutList.add(proxyRollout);
} }
return proxyRolloutList; return proxyRolloutList;
@@ -148,7 +157,8 @@ public class RolloutBeanQuery extends AbstractBeanQuery<ProxyRollout> {
* .util.List, java.util.List, java.util.List) * .util.List, java.util.List, java.util.List)
*/ */
@Override @Override
protected void saveBeans(final List<ProxyRollout> arg0, final List<ProxyRollout> arg1, final List<ProxyRollout> arg2) { protected void saveBeans(final List<ProxyRollout> arg0, final List<ProxyRollout> arg1,
final List<ProxyRollout> arg2) {
/** /**
* CRUD operations on Target will be done through repository methods * CRUD operations on Target will be done through repository methods
*/ */

View File

@@ -8,23 +8,31 @@
*/ */
package org.eclipse.hawkbit.ui.rollout.rollout; package org.eclipse.hawkbit.ui.rollout.rollout;
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.HTML_LI_CLOSE_TAG;
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.HTML_LI_OPEN_TAG;
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.HTML_UL_CLOSE_TAG;
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.HTML_UL_OPEN_TAG;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.eclipse.hawkbit.eventbus.event.RolloutChangeEvent; import org.eclipse.hawkbit.eventbus.event.RolloutChangeEvent;
import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.SpPermissionChecker;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid; import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlButtonRenderer; import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlButtonRenderer;
import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlLabelRenderer; import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlLabelRenderer;
import org.eclipse.hawkbit.ui.customrenderers.renderers.LinkRenderer; import org.eclipse.hawkbit.ui.customrenderers.renderers.RolloutRenderer;
import org.eclipse.hawkbit.ui.rollout.DistributionBarHelper; import org.eclipse.hawkbit.ui.rollout.DistributionBarHelper;
import org.eclipse.hawkbit.ui.rollout.StatusFontIcon; import org.eclipse.hawkbit.ui.rollout.StatusFontIcon;
import org.eclipse.hawkbit.ui.rollout.event.RolloutEvent; import org.eclipse.hawkbit.ui.rollout.event.RolloutEvent;
@@ -77,6 +85,13 @@ public class RolloutListGrid extends AbstractGrid {
private static final String START_OPTION = "Start"; private static final String START_OPTION = "Start";
private static final String DS_TYPE = "type";
private static final String SW_MODULES = "swModules";
private static final String IS_REQUIRED_MIGRATION_STEP = "isRequiredMigrationStep";
private static final String ROLLOUT_RENDERER_DATA = "rolloutRendererData";
@Autowired @Autowired
private transient RolloutManagement rolloutManagement; private transient RolloutManagement rolloutManagement;
@@ -95,7 +110,10 @@ public class RolloutListGrid extends AbstractGrid {
private transient Map<RolloutStatus, StatusFontIcon> statusIconMap = new EnumMap<>(RolloutStatus.class); private transient Map<RolloutStatus, StatusFontIcon> statusIconMap = new EnumMap<>(RolloutStatus.class);
/**
* Handles the RolloutEvent to refresh Grid.
*
*/
@EventBusListenerMethod(scope = EventScope.SESSION) @EventBusListenerMethod(scope = EventScope.SESSION)
void onEvent(final RolloutEvent event) { void onEvent(final RolloutEvent event) {
switch (event) { switch (event) {
@@ -132,10 +150,16 @@ public class RolloutListGrid extends AbstractGrid {
item.getItemProperty(SPUILabelDefinitions.VAR_STATUS).setValue(rollout.getStatus()); item.getItemProperty(SPUILabelDefinitions.VAR_STATUS).setValue(rollout.getStatus());
item.getItemProperty(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS).setValue(totalTargetCountStatus); item.getItemProperty(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS).setValue(totalTargetCountStatus);
final Long groupCount = (Long) item.getItemProperty(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS).getValue(); final Long groupCount = (Long) item.getItemProperty(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS).getValue();
if (rollout.getRolloutGroups() != null && groupCount != rollout.getRolloutGroups().size()) { final int groupsCreated = rollout.getRolloutGroupsCreated();
if (groupsCreated != 0) {
item.getItemProperty(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS).setValue(Long.valueOf(groupsCreated));
} else if (rollout.getRolloutGroups() != null && groupCount != rollout.getRolloutGroups().size()) {
item.getItemProperty(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS) item.getItemProperty(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS)
.setValue(Long.valueOf(rollout.getRolloutGroups().size())); .setValue(Long.valueOf(rollout.getRolloutGroups().size()));
} }
item.getItemProperty(ROLLOUT_RENDERER_DATA)
.setValue(new RolloutRendererData(rollout.getName(), rollout.getStatus().toString()));
} }
@Override @Override
@@ -149,7 +173,11 @@ public class RolloutListGrid extends AbstractGrid {
protected void addContainerProperties() { protected void addContainerProperties() {
final LazyQueryContainer rolloutGridContainer = (LazyQueryContainer) getContainerDataSource(); final LazyQueryContainer rolloutGridContainer = (LazyQueryContainer) getContainerDataSource();
rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_NAME, String.class, "", false, false); rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_NAME, String.class, "", false, false);
rolloutGridContainer.addContainerProperty(DS_TYPE, String.class, null, false, false);
rolloutGridContainer.addContainerProperty(SW_MODULES, Set.class, null, false, false);
rolloutGridContainer.addContainerProperty(ROLLOUT_RENDERER_DATA, RolloutRendererData.class, null, false, false);
rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_DESC, String.class, null, false, false); rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_DESC, String.class, null, false, false);
rolloutGridContainer.addContainerProperty(IS_REQUIRED_MIGRATION_STEP, boolean.class, null, false, false);
rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_STATUS, RolloutStatus.class, null, false, rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_STATUS, RolloutStatus.class, null, false,
false); false);
rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_DIST_NAME_VERSION, String.class, null, false, rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_DIST_NAME_VERSION, String.class, null, false,
@@ -163,7 +191,7 @@ public class RolloutListGrid extends AbstractGrid {
false); false);
rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_MODIFIED_BY, String.class, null, false, rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_MODIFIED_BY, String.class, null, false,
false); false);
rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS, Integer.class, 0, false, rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS, Long.class, 0, false,
false); false);
rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_TOTAL_TARGETS, String.class, "0", false, rolloutGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_TOTAL_TARGETS, String.class, "0", false,
false); false);
@@ -177,8 +205,9 @@ public class RolloutListGrid extends AbstractGrid {
@Override @Override
protected void setColumnExpandRatio() { protected void setColumnExpandRatio() {
getColumn(SPUILabelDefinitions.VAR_NAME).setMinimumWidth(40);
getColumn(SPUILabelDefinitions.VAR_NAME).setMaximumWidth(150); getColumn(ROLLOUT_RENDERER_DATA).setMinimumWidth(40);
getColumn(ROLLOUT_RENDERER_DATA).setMaximumWidth(150);
getColumn(SPUILabelDefinitions.VAR_DIST_NAME_VERSION).setMinimumWidth(40); getColumn(SPUILabelDefinitions.VAR_DIST_NAME_VERSION).setMinimumWidth(40);
getColumn(SPUILabelDefinitions.VAR_DIST_NAME_VERSION).setMaximumWidth(150); getColumn(SPUILabelDefinitions.VAR_DIST_NAME_VERSION).setMaximumWidth(150);
@@ -202,7 +231,10 @@ public class RolloutListGrid extends AbstractGrid {
@Override @Override
protected void setColumnHeaderNames() { protected void setColumnHeaderNames() {
getColumn(SPUILabelDefinitions.VAR_NAME).setHeaderCaption(i18n.get("header.name")); getColumn(ROLLOUT_RENDERER_DATA).setHeaderCaption(i18n.get("header.name"));
getColumn(DS_TYPE).setHeaderCaption("Type");
getColumn(SW_MODULES).setHeaderCaption("swModules");
getColumn(IS_REQUIRED_MIGRATION_STEP).setHeaderCaption("IsRequiredMigrationStep");
getColumn(SPUILabelDefinitions.VAR_DIST_NAME_VERSION).setHeaderCaption(i18n.get("header.distributionset")); getColumn(SPUILabelDefinitions.VAR_DIST_NAME_VERSION).setHeaderCaption(i18n.get("header.distributionset"));
getColumn(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS).setHeaderCaption(i18n.get("header.numberofgroups")); getColumn(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS).setHeaderCaption(i18n.get("header.numberofgroups"));
getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS).setHeaderCaption(i18n.get("header.total.targets")); getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS).setHeaderCaption(i18n.get("header.total.targets"));
@@ -225,8 +257,11 @@ public class RolloutListGrid extends AbstractGrid {
@Override @Override
protected void setColumnProperties() { protected void setColumnProperties() {
final List<Object> columnList = new ArrayList<>(); final List<Object> columnList = new ArrayList<>();
columnList.add(SPUILabelDefinitions.VAR_NAME); columnList.add(ROLLOUT_RENDERER_DATA);
columnList.add(SPUILabelDefinitions.VAR_DIST_NAME_VERSION); columnList.add(SPUILabelDefinitions.VAR_DIST_NAME_VERSION);
columnList.add(DS_TYPE);
columnList.add(SW_MODULES);
columnList.add(IS_REQUIRED_MIGRATION_STEP);
columnList.add(SPUILabelDefinitions.VAR_STATUS); columnList.add(SPUILabelDefinitions.VAR_STATUS);
columnList.add(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS); columnList.add(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS);
columnList.add(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS); columnList.add(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS);
@@ -245,11 +280,15 @@ public class RolloutListGrid extends AbstractGrid {
@Override @Override
protected void setHiddenColumns() { protected void setHiddenColumns() {
final List<Object> columnsToBeHidden = new ArrayList<>(); final List<Object> columnsToBeHidden = new ArrayList<>();
columnsToBeHidden.add(SPUILabelDefinitions.VAR_NAME);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_DATE); columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_DATE);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_USER); columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_USER);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_MODIFIED_DATE); columnsToBeHidden.add(SPUILabelDefinitions.VAR_MODIFIED_DATE);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_MODIFIED_BY); columnsToBeHidden.add(SPUILabelDefinitions.VAR_MODIFIED_BY);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_DESC); columnsToBeHidden.add(SPUILabelDefinitions.VAR_DESC);
columnsToBeHidden.add(IS_REQUIRED_MIGRATION_STEP);
columnsToBeHidden.add(DS_TYPE);
columnsToBeHidden.add(SW_MODULES);
for (final Object propertyId : columnsToBeHidden) { for (final Object propertyId : columnsToBeHidden) {
getColumn(propertyId).setHidden(true); getColumn(propertyId).setHidden(true);
} }
@@ -263,6 +302,8 @@ public class RolloutListGrid extends AbstractGrid {
@Override @Override
protected void addColumnRenderes() { protected void addColumnRenderes() {
getColumn(SPUILabelDefinitions.VAR_NUMBER_OF_GROUPS).setRenderer(new HtmlRenderer(),
new TotalTargetGroupsConverter());
getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS).setRenderer(new HtmlRenderer(), getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS).setRenderer(new HtmlRenderer(),
new TotalTargetCountStatusConverter()); new TotalTargetCountStatusConverter());
@@ -270,7 +311,11 @@ public class RolloutListGrid extends AbstractGrid {
getColumn(SPUILabelDefinitions.VAR_STATUS).setRenderer(new HtmlLabelRenderer(), new RolloutStatusConverter()); getColumn(SPUILabelDefinitions.VAR_STATUS).setRenderer(new HtmlLabelRenderer(), new RolloutStatusConverter());
getColumn(SPUILabelDefinitions.ACTION).setRenderer(new HtmlButtonRenderer(event -> onClickOfActionBtn(event))); getColumn(SPUILabelDefinitions.ACTION).setRenderer(new HtmlButtonRenderer(event -> onClickOfActionBtn(event)));
getColumn(SPUILabelDefinitions.VAR_NAME).setRenderer(new LinkRenderer(event -> onClickOfRolloutName(event)));
final RolloutRenderer customObjectRenderer = new RolloutRenderer(RolloutRendererData.class);
customObjectRenderer.addClickListener(event -> onClickOfRolloutName(event));
getColumn(ROLLOUT_RENDERER_DATA).setRenderer(customObjectRenderer);
} }
private void createRolloutStatusToFontMap() { private void createRolloutStatusToFontMap() {
@@ -403,6 +448,9 @@ public class RolloutListGrid extends AbstractGrid {
((LazyQueryContainer) getContainerDataSource()).refresh(); ((LazyQueryContainer) getContainerDataSource()).refresh();
} }
/**
* Generator to generate fontIcon by String.
*/
public final class FontIconGenerator extends PropertyValueGenerator<String> { public final class FontIconGenerator extends PropertyValueGenerator<String> {
private static final long serialVersionUID = 2544026030795375748L; private static final long serialVersionUID = 2544026030795375748L;
@@ -428,15 +476,54 @@ public class RolloutListGrid extends AbstractGrid {
return cell.getProperty().getValue().toString().toLowerCase(); return cell.getProperty().getValue().toString().toLowerCase();
} else if (SPUILabelDefinitions.ACTION.equals(cell.getPropertyId())) { } else if (SPUILabelDefinitions.ACTION.equals(cell.getPropertyId())) {
return SPUILabelDefinitions.ACTION.toLowerCase(); return SPUILabelDefinitions.ACTION.toLowerCase();
} else if (SPUILabelDefinitions.VAR_NAME.equals(cell.getPropertyId())) { } else if (ROLLOUT_RENDERER_DATA.equals(cell.getPropertyId())) {
return cell.getProperty().getValue().toString(); return ((RolloutRendererData) cell.getProperty().getValue()).getName();
} else if (SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS.equals(cell.getPropertyId())) { } else if (SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS.equals(cell.getPropertyId())) {
return DistributionBarHelper return DistributionBarHelper
.getTooltip(((TotalTargetCountStatus) cell.getValue()).getStatusTotalCountMap()); .getTooltip(((TotalTargetCountStatus) cell.getValue()).getStatusTotalCountMap());
} else if (SPUILabelDefinitions.VAR_DIST_NAME_VERSION.equals(cell.getPropertyId())) {
return getDSDetails(cell.getItem());
} }
return null; return null;
} }
private String getDSDetails(final Item rolloutItem) {
final StringBuilder swModuleNames = new StringBuilder();
final StringBuilder swModuleVendors = new StringBuilder();
final Set<SoftwareModule> swModules = (Set<SoftwareModule>) rolloutItem.getItemProperty(SW_MODULES).getValue();
swModules.forEach(swModule -> {
swModuleNames.append(swModule.getName());
swModuleNames.append(" , ");
swModuleVendors.append(swModule.getVendor());
swModuleVendors.append(" , ");
});
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(HTML_UL_OPEN_TAG);
stringBuilder.append(HTML_LI_OPEN_TAG);
stringBuilder.append(" DistributionSet Description : ")
.append((String) rolloutItem.getItemProperty(SPUILabelDefinitions.VAR_DESC).getValue());
stringBuilder.append(HTML_LI_CLOSE_TAG);
stringBuilder.append(HTML_LI_OPEN_TAG);
stringBuilder.append(" DistributionSet Type : ")
.append((String) rolloutItem.getItemProperty(DS_TYPE).getValue());
stringBuilder.append(HTML_LI_CLOSE_TAG);
stringBuilder.append(HTML_LI_OPEN_TAG);
stringBuilder.append("Required Migration step : ")
.append((boolean) rolloutItem.getItemProperty(IS_REQUIRED_MIGRATION_STEP).getValue() ? "Yes" : "No");
stringBuilder.append(HTML_LI_CLOSE_TAG);
stringBuilder.append(HTML_LI_OPEN_TAG);
stringBuilder.append("SoftWare Modules : ").append(swModuleNames.toString());
stringBuilder.append(HTML_LI_CLOSE_TAG);
stringBuilder.append(HTML_LI_OPEN_TAG);
stringBuilder.append("Vendor(s) : ").append(swModuleVendors.toString());
stringBuilder.append(HTML_LI_CLOSE_TAG);
stringBuilder.append(HTML_UL_CLOSE_TAG);
return stringBuilder.toString();
}
enum ACTION { enum ACTION {
PAUSE, RESUME, START, UPDATE PAUSE, RESUME, START, UPDATE
} }
@@ -568,4 +655,39 @@ public class RolloutListGrid extends AbstractGrid {
} }
} }
/**
* Converter to convert 0 to empty, if total target groups is zero.
*
*/
class TotalTargetGroupsConverter implements Converter<String, Long> {
private static final long serialVersionUID = 6589305227035220369L;
@Override
public Long convertToModel(final String value, final Class<? extends Long> targetType, final Locale locale)
throws com.vaadin.data.util.converter.Converter.ConversionException {
return null;
}
@Override
public String convertToPresentation(final Long value, final Class<? extends String> targetType,
final Locale locale) throws com.vaadin.data.util.converter.Converter.ConversionException {
if (value == 0) {
return "";
}
return value.toString();
}
@Override
public Class<Long> getModelType() {
return Long.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
}
} }

View File

@@ -9,200 +9,211 @@
package org.eclipse.hawkbit.ui.rollout.rolloutgroup; package org.eclipse.hawkbit.ui.rollout.rolloutgroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
/** /**
* Proxy rollout group with suctome properties. * Proxy rollout group with renderer properties.
* *
*/ */
public class ProxyRolloutGroup extends RolloutGroup { public class ProxyRolloutGroup extends RolloutGroup {
private static final long serialVersionUID = -2745056813306692356L; private static final long serialVersionUID = -2745056813306692356L;
private String createdDate; private String createdDate;
private String modifiedDate; private String modifiedDate;
private String finishedPercentage; private String finishedPercentage;
private Long runningTargetsCount; private Long runningTargetsCount;
private Long scheduledTargetsCount; private Long scheduledTargetsCount;
private Long cancelledTargetsCount; private Long cancelledTargetsCount;
private Long errorTargetsCount; private Long errorTargetsCount;
private Long finishedTargetsCount; private Long finishedTargetsCount;
private Long notStartedTargetsCount; private Long notStartedTargetsCount;
private Boolean isActionRecieved = Boolean.FALSE; private Boolean isActionRecieved = Boolean.FALSE;
private String totalTargetsCount; private String totalTargetsCount;
/** private RolloutRendererData rolloutRendererData;
* @return the createdDate
*/
public String getCreatedDate() {
return createdDate;
}
/** public RolloutRendererData getRolloutRendererData() {
* @param createdDate return rolloutRendererData;
* the createdDate to set }
*/
public void setCreatedDate(final String createdDate) {
this.createdDate = createdDate;
}
/** public void setRolloutRendererData(RolloutRendererData rendererData) {
* @return the modifiedDate this.rolloutRendererData = rendererData;
*/ }
public String getModifiedDate() {
return modifiedDate;
}
/** /**
* @param modifiedDate * @return the createdDate
* the modifiedDate to set */
*/ public String getCreatedDate() {
public void setModifiedDate(final String modifiedDate) { return createdDate;
this.modifiedDate = modifiedDate; }
}
/** /**
* @return the finishedPercentage * @param createdDate
*/ * the createdDate to set
public String getFinishedPercentage() { */
return finishedPercentage; public void setCreatedDate(final String createdDate) {
} this.createdDate = createdDate;
}
/** /**
* @param finishedPercentage * @return the modifiedDate
* the finishedPercentage to set */
*/ public String getModifiedDate() {
public void setFinishedPercentage(final String finishedPercentage) { return modifiedDate;
this.finishedPercentage = finishedPercentage; }
}
/** /**
* @return the runningTargetsCount * @param modifiedDate
*/ * the modifiedDate to set
public Long getRunningTargetsCount() { */
return runningTargetsCount; public void setModifiedDate(final String modifiedDate) {
} this.modifiedDate = modifiedDate;
}
/** /**
* @param runningTargetsCount * @return the finishedPercentage
* the runningTargetsCount to set */
*/ public String getFinishedPercentage() {
public void setRunningTargetsCount(final Long runningTargetsCount) { return finishedPercentage;
this.runningTargetsCount = runningTargetsCount; }
}
/** /**
* @return the scheduledTargetsCount * @param finishedPercentage
*/ * the finishedPercentage to set
public Long getScheduledTargetsCount() { */
return scheduledTargetsCount; public void setFinishedPercentage(final String finishedPercentage) {
} this.finishedPercentage = finishedPercentage;
}
/** /**
* @param scheduledTargetsCount * @return the runningTargetsCount
* the scheduledTargetsCount to set */
*/ public Long getRunningTargetsCount() {
public void setScheduledTargetsCount(final Long scheduledTargetsCount) { return runningTargetsCount;
this.scheduledTargetsCount = scheduledTargetsCount; }
}
/** /**
* @return the cancelledTargetsCount * @param runningTargetsCount
*/ * the runningTargetsCount to set
public Long getCancelledTargetsCount() { */
return cancelledTargetsCount; public void setRunningTargetsCount(final Long runningTargetsCount) {
} this.runningTargetsCount = runningTargetsCount;
}
/** /**
* @param cancelledTargetsCount * @return the scheduledTargetsCount
* the cancelledTargetsCount to set */
*/ public Long getScheduledTargetsCount() {
public void setCancelledTargetsCount(final Long cancelledTargetsCount) { return scheduledTargetsCount;
this.cancelledTargetsCount = cancelledTargetsCount; }
}
/** /**
* @return the errorTargetsCount * @param scheduledTargetsCount
*/ * the scheduledTargetsCount to set
public Long getErrorTargetsCount() { */
return errorTargetsCount; public void setScheduledTargetsCount(final Long scheduledTargetsCount) {
} this.scheduledTargetsCount = scheduledTargetsCount;
}
/** /**
* @param errorTargetsCount * @return the cancelledTargetsCount
* the errorTargetsCount to set */
*/ public Long getCancelledTargetsCount() {
public void setErrorTargetsCount(final Long errorTargetsCount) { return cancelledTargetsCount;
this.errorTargetsCount = errorTargetsCount; }
}
/** /**
* @return the finishedTargetsCount * @param cancelledTargetsCount
*/ * the cancelledTargetsCount to set
public Long getFinishedTargetsCount() { */
return finishedTargetsCount; public void setCancelledTargetsCount(final Long cancelledTargetsCount) {
} this.cancelledTargetsCount = cancelledTargetsCount;
}
/** /**
* @param finishedTargetsCount * @return the errorTargetsCount
* the finishedTargetsCount to set */
*/ public Long getErrorTargetsCount() {
public void setFinishedTargetsCount(final Long finishedTargetsCount) { return errorTargetsCount;
this.finishedTargetsCount = finishedTargetsCount; }
}
/** /**
* @return the notStartedTargetsCount * @param errorTargetsCount
*/ * the errorTargetsCount to set
public Long getNotStartedTargetsCount() { */
return notStartedTargetsCount; public void setErrorTargetsCount(final Long errorTargetsCount) {
} this.errorTargetsCount = errorTargetsCount;
}
/** /**
* @param notStartedTargetsCount * @return the finishedTargetsCount
* the notStartedTargetsCount to set */
*/ public Long getFinishedTargetsCount() {
public void setNotStartedTargetsCount(final Long notStartedTargetsCount) { return finishedTargetsCount;
this.notStartedTargetsCount = notStartedTargetsCount; }
}
/** /**
* @return the isActionRecieved * @param finishedTargetsCount
*/ * the finishedTargetsCount to set
public Boolean getIsActionRecieved() { */
return isActionRecieved; public void setFinishedTargetsCount(final Long finishedTargetsCount) {
} this.finishedTargetsCount = finishedTargetsCount;
}
/** /**
* @param isActionRecieved * @return the notStartedTargetsCount
* the isActionRecieved to set */
*/ public Long getNotStartedTargetsCount() {
public void setIsActionRecieved(final Boolean isActionRecieved) { return notStartedTargetsCount;
this.isActionRecieved = isActionRecieved; }
}
/** /**
* @return the totalTargetsCount * @param notStartedTargetsCount
*/ * the notStartedTargetsCount to set
public String getTotalTargetsCount() { */
return totalTargetsCount; public void setNotStartedTargetsCount(final Long notStartedTargetsCount) {
} this.notStartedTargetsCount = notStartedTargetsCount;
}
/** /**
* @param totalTargetsCount * @return the isActionRecieved
* the totalTargetsCount to set */
*/ public Boolean getIsActionRecieved() {
public void setTotalTargetsCount(final String totalTargetsCount) { return isActionRecieved;
this.totalTargetsCount = totalTargetsCount; }
}
/**
* @param isActionRecieved
* the isActionRecieved to set
*/
public void setIsActionRecieved(final Boolean isActionRecieved) {
this.isActionRecieved = isActionRecieved;
}
/**
* @return the totalTargetsCount
*/
public String getTotalTargetsCount() {
return totalTargetsCount;
}
/**
* @param totalTargetsCount
* the totalTargetsCount to set
*/
public void setTotalTargetsCount(final String totalTargetsCount) {
this.totalTargetsCount = totalTargetsCount;
}
} }

View File

@@ -15,6 +15,8 @@ import java.util.Map;
import org.eclipse.hawkbit.repository.RolloutGroupManagement; import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState; import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
@@ -110,8 +112,8 @@ public class RolloutGroupBeanQuery extends AbstractBeanQuery<ProxyRolloutGroup>
proxyRolloutGroup.setDescription(rolloutGroup.getDescription()); proxyRolloutGroup.setDescription(rolloutGroup.getDescription());
proxyRolloutGroup.setCreatedDate(SPDateTimeUtil.getFormattedDate(rolloutGroup.getCreatedAt())); proxyRolloutGroup.setCreatedDate(SPDateTimeUtil.getFormattedDate(rolloutGroup.getCreatedAt()));
proxyRolloutGroup.setModifiedDate(SPDateTimeUtil.getFormattedDate(rolloutGroup.getLastModifiedAt())); proxyRolloutGroup.setModifiedDate(SPDateTimeUtil.getFormattedDate(rolloutGroup.getLastModifiedAt()));
proxyRolloutGroup.setCreatedBy(HawkbitCommonUtil.getIMUser(rolloutGroup.getCreatedBy())); proxyRolloutGroup.setCreatedBy(UserDetailsFormatter.loadAndFormatCreatedBy(rolloutGroup));
proxyRolloutGroup.setLastModifiedBy(HawkbitCommonUtil.getIMUser(rolloutGroup.getLastModifiedBy())); proxyRolloutGroup.setLastModifiedBy(UserDetailsFormatter.loadAndFormatLastModifiedBy(rolloutGroup));
proxyRolloutGroup.setId(rolloutGroup.getId()); proxyRolloutGroup.setId(rolloutGroup.getId());
proxyRolloutGroup.setStatus(rolloutGroup.getStatus()); proxyRolloutGroup.setStatus(rolloutGroup.getStatus());
proxyRolloutGroup.setErrorAction(rolloutGroup.getErrorAction()); proxyRolloutGroup.setErrorAction(rolloutGroup.getErrorAction());
@@ -122,6 +124,8 @@ public class RolloutGroupBeanQuery extends AbstractBeanQuery<ProxyRolloutGroup>
proxyRolloutGroup.setSuccessConditionExp(rolloutGroup.getSuccessConditionExp()); proxyRolloutGroup.setSuccessConditionExp(rolloutGroup.getSuccessConditionExp());
proxyRolloutGroup.setFinishedPercentage(calculateFinishedPercentage(rolloutGroup)); proxyRolloutGroup.setFinishedPercentage(calculateFinishedPercentage(rolloutGroup));
proxyRolloutGroup.setRolloutRendererData(new RolloutRendererData(rolloutGroup.getName(), null));
proxyRolloutGroup.setTotalTargetsCount(String.valueOf(rolloutGroup.getTotalTargets())); proxyRolloutGroup.setTotalTargetsCount(String.valueOf(rolloutGroup.getTotalTargets()));
proxyRolloutGroup.setTotalTargetCountStatus(rolloutGroup.getTotalTargetCountStatus()); proxyRolloutGroup.setTotalTargetCountStatus(rolloutGroup.getTotalTargetCountStatus());

View File

@@ -17,13 +17,15 @@ import java.util.Map;
import org.eclipse.hawkbit.eventbus.event.RolloutGroupChangeEvent; import org.eclipse.hawkbit.eventbus.event.RolloutGroupChangeEvent;
import org.eclipse.hawkbit.repository.RolloutGroupManagement; import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.SpPermissionChecker;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid; import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.RolloutRendererData;
import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlLabelRenderer; import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlLabelRenderer;
import org.eclipse.hawkbit.ui.customrenderers.renderers.LinkRenderer; import org.eclipse.hawkbit.ui.customrenderers.renderers.RolloutRenderer;
import org.eclipse.hawkbit.ui.rollout.DistributionBarHelper; import org.eclipse.hawkbit.ui.rollout.DistributionBarHelper;
import org.eclipse.hawkbit.ui.rollout.StatusFontIcon; import org.eclipse.hawkbit.ui.rollout.StatusFontIcon;
import org.eclipse.hawkbit.ui.rollout.event.RolloutEvent; import org.eclipse.hawkbit.ui.rollout.event.RolloutEvent;
@@ -59,9 +61,14 @@ import com.vaadin.ui.renderers.HtmlRenderer;
public class RolloutGroupListGrid extends AbstractGrid { public class RolloutGroupListGrid extends AbstractGrid {
private static final long serialVersionUID = 4060904914954370524L; private static final long serialVersionUID = 4060904914954370524L;
private static final String ROLLOUT_RENDERER_DATA = "rolloutRendererData";
@Autowired @Autowired
private transient RolloutGroupManagement rolloutGroupManagement; private transient RolloutGroupManagement rolloutGroupManagement;
@Autowired
private transient RolloutManagement rolloutManagement;
@Autowired @Autowired
private transient RolloutUIState rolloutUIState; private transient RolloutUIState rolloutUIState;
@@ -103,6 +110,13 @@ public class RolloutGroupListGrid extends AbstractGrid {
item.getItemProperty(SPUILabelDefinitions.VAR_STATUS).setValue(rolloutGroup.getStatus()); item.getItemProperty(SPUILabelDefinitions.VAR_STATUS).setValue(rolloutGroup.getStatus());
item.getItemProperty(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS) item.getItemProperty(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS)
.setValue(rolloutGroup.getTotalTargetCountStatus()); .setValue(rolloutGroup.getTotalTargetCountStatus());
item.getItemProperty(SPUILabelDefinitions.ROLLOUT_GROUP_INSTALLED_PERCENTAGE)
.setValue(calculateFinishedPercentage(rolloutGroup));
}
private String calculateFinishedPercentage(final RolloutGroup rolloutGroup) {
return HawkbitCommonUtil.formattingFinishedPercentage(rolloutGroup,
rolloutManagement.getFinishedPercentForRunningGroup(rolloutGroup.getRollout().getId(), rolloutGroup));
} }
@Override @Override
@@ -116,6 +130,9 @@ public class RolloutGroupListGrid extends AbstractGrid {
protected void addContainerProperties() { protected void addContainerProperties() {
final LazyQueryContainer rolloutGroupGridContainer = (LazyQueryContainer) getContainerDataSource(); final LazyQueryContainer rolloutGroupGridContainer = (LazyQueryContainer) getContainerDataSource();
rolloutGroupGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_NAME, String.class, "", false, false); rolloutGroupGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_NAME, String.class, "", false, false);
rolloutGroupGridContainer.addContainerProperty(ROLLOUT_RENDERER_DATA, RolloutRendererData.class, null, false,
false);
rolloutGroupGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_DESC, String.class, null, false, false); rolloutGroupGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_DESC, String.class, null, false, false);
rolloutGroupGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_STATUS, RolloutGroupStatus.class, null, rolloutGroupGridContainer.addContainerProperty(SPUILabelDefinitions.VAR_STATUS, RolloutGroupStatus.class, null,
false, false); false, false);
@@ -145,8 +162,8 @@ public class RolloutGroupListGrid extends AbstractGrid {
@Override @Override
protected void setColumnExpandRatio() { protected void setColumnExpandRatio() {
getColumn(SPUILabelDefinitions.VAR_NAME).setMinimumWidth(40); getColumn(ROLLOUT_RENDERER_DATA).setMinimumWidth(40);
getColumn(SPUILabelDefinitions.VAR_NAME).setMaximumWidth(200); getColumn(ROLLOUT_RENDERER_DATA).setMaximumWidth(200);
getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS).setMinimumWidth(40); getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS).setMinimumWidth(40);
getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS).setMaximumWidth(100); getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS).setMaximumWidth(100);
@@ -170,7 +187,7 @@ public class RolloutGroupListGrid extends AbstractGrid {
@Override @Override
protected void setColumnHeaderNames() { protected void setColumnHeaderNames() {
getColumn(SPUILabelDefinitions.VAR_NAME).setHeaderCaption(i18n.get("header.name")); getColumn(ROLLOUT_RENDERER_DATA).setHeaderCaption(i18n.get("header.name"));
getColumn(SPUILabelDefinitions.VAR_STATUS).setHeaderCaption(i18n.get("header.status")); getColumn(SPUILabelDefinitions.VAR_STATUS).setHeaderCaption(i18n.get("header.status"));
getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS) getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS)
.setHeaderCaption(i18n.get("header.detail.status")); .setHeaderCaption(i18n.get("header.detail.status"));
@@ -196,7 +213,7 @@ public class RolloutGroupListGrid extends AbstractGrid {
@Override @Override
protected void setColumnProperties() { protected void setColumnProperties() {
final List<Object> columnList = new ArrayList<>(); final List<Object> columnList = new ArrayList<>();
columnList.add(SPUILabelDefinitions.VAR_NAME); columnList.add(ROLLOUT_RENDERER_DATA);
columnList.add(SPUILabelDefinitions.VAR_STATUS); columnList.add(SPUILabelDefinitions.VAR_STATUS);
columnList.add(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS); columnList.add(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS);
columnList.add(SPUILabelDefinitions.VAR_TOTAL_TARGETS); columnList.add(SPUILabelDefinitions.VAR_TOTAL_TARGETS);
@@ -221,14 +238,15 @@ public class RolloutGroupListGrid extends AbstractGrid {
getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS).setRenderer(new HtmlRenderer(), getColumn(SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS).setRenderer(new HtmlRenderer(),
new TotalTargetCountStatusConverter()); new TotalTargetCountStatusConverter());
if (permissionChecker.hasRolloutTargetsReadPermission()) { if (permissionChecker.hasRolloutTargetsReadPermission()) {
getColumn(SPUILabelDefinitions.VAR_NAME) getColumn(ROLLOUT_RENDERER_DATA)
.setRenderer(new LinkRenderer(event -> onClickOfRolloutGroupName(event))); .setRenderer(new RolloutRenderer(event -> onClickOfRolloutGroupName(event)));
} }
} }
@Override @Override
protected void setHiddenColumns() { protected void setHiddenColumns() {
final List<Object> columnsToBeHidden = new ArrayList<>(); final List<Object> columnsToBeHidden = new ArrayList<>();
columnsToBeHidden.add(SPUILabelDefinitions.VAR_NAME);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_DATE); columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_DATE);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_USER); columnsToBeHidden.add(SPUILabelDefinitions.VAR_CREATED_USER);
columnsToBeHidden.add(SPUILabelDefinitions.VAR_MODIFIED_DATE); columnsToBeHidden.add(SPUILabelDefinitions.VAR_MODIFIED_DATE);
@@ -268,8 +286,8 @@ public class RolloutGroupListGrid extends AbstractGrid {
return cell.getProperty().getValue().toString().toLowerCase(); return cell.getProperty().getValue().toString().toLowerCase();
} else if (SPUILabelDefinitions.ACTION.equals(cell.getPropertyId())) { } else if (SPUILabelDefinitions.ACTION.equals(cell.getPropertyId())) {
return SPUILabelDefinitions.ACTION.toLowerCase(); return SPUILabelDefinitions.ACTION.toLowerCase();
} else if (SPUILabelDefinitions.VAR_NAME.equals(cell.getPropertyId())) { } else if (ROLLOUT_RENDERER_DATA.equals(cell.getPropertyId())) {
return cell.getProperty().getValue().toString(); return ((RolloutRendererData) cell.getProperty().getValue()).getName();
} else if (SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS.equals(cell.getPropertyId())) { } else if (SPUILabelDefinitions.VAR_TOTAL_TARGETS_COUNT_STATUS.equals(cell.getPropertyId())) {
return DistributionBarHelper return DistributionBarHelper
.getTooltip(((TotalTargetCountStatus) cell.getValue()).getStatusTotalCountMap()); .getTooltip(((TotalTargetCountStatus) cell.getValue()).getStatusTotalCountMap());
@@ -306,14 +324,14 @@ public class RolloutGroupListGrid extends AbstractGrid {
@Override @Override
public TotalTargetCountStatus convertToModel(final String value, public TotalTargetCountStatus convertToModel(final String value,
final Class<? extends TotalTargetCountStatus> targetType, final Locale locale) final Class<? extends TotalTargetCountStatus> targetType, final Locale locale)
throws com.vaadin.data.util.converter.Converter.ConversionException { throws com.vaadin.data.util.converter.Converter.ConversionException {
return null; return null;
} }
@Override @Override
public String convertToPresentation(final TotalTargetCountStatus value, public String convertToPresentation(final TotalTargetCountStatus value,
final Class<? extends String> targetType, final Locale locale) final Class<? extends String> targetType, final Locale locale)
throws com.vaadin.data.util.converter.Converter.ConversionException { throws com.vaadin.data.util.converter.Converter.ConversionException {
return DistributionBarHelper.getDistributionBarAsHTMLString(value.getStatusTotalCountMap()); return DistributionBarHelper.getDistributionBarAsHTMLString(value.getStatusTotalCountMap());
} }

View File

@@ -161,6 +161,7 @@ public class RolloutGroupsListHeader extends AbstractGridHeader {
final HorizontalLayout headerCaptionLayout = new HorizontalLayout(); final HorizontalLayout headerCaptionLayout = new HorizontalLayout();
headerCaptionLayout.addComponent(rolloutsListViewLink); headerCaptionLayout.addComponent(rolloutsListViewLink);
headerCaptionLayout.addComponent(new Label(">")); headerCaptionLayout.addComponent(new Label(">"));
headerCaption.addStyleName("breadcrumbPaddingLeft");
headerCaptionLayout.addComponent(headerCaption); headerCaptionLayout.addComponent(headerCaption);
return headerCaptionLayout; return headerCaptionLayout;

View File

@@ -17,6 +17,7 @@ import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetWithActionStatus; import org.eclipse.hawkbit.repository.model.TargetWithActionStatus;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.components.ProxyTarget; import org.eclipse.hawkbit.ui.components.ProxyTarget;
import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState; import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
@@ -105,8 +106,8 @@ public class RolloutGroupTargetsBeanQuery extends AbstractBeanQuery<ProxyTarget>
prxyTarget.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(targ.getLastModifiedAt())); prxyTarget.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(targ.getLastModifiedAt()));
prxyTarget.setCreatedDate(SPDateTimeUtil.getFormattedDate(targ.getCreatedAt())); prxyTarget.setCreatedDate(SPDateTimeUtil.getFormattedDate(targ.getCreatedAt()));
prxyTarget.setCreatedAt(targ.getCreatedAt()); prxyTarget.setCreatedAt(targ.getCreatedAt());
prxyTarget.setCreatedByUser(HawkbitCommonUtil.getIMUser(targ.getCreatedBy())); prxyTarget.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(targ));
prxyTarget.setModifiedByUser(HawkbitCommonUtil.getIMUser(targ.getLastModifiedBy())); prxyTarget.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(targ));
if (targetWithActionStatus.getStatus() != null) { if (targetWithActionStatus.getStatus() != null) {
prxyTarget.setStatus(targetWithActionStatus.getStatus()); prxyTarget.setStatus(targetWithActionStatus.getStatus());
} }

Some files were not shown because too many files have changed in this diff Show More