diff --git a/README.md b/README.md index 0a9b0b4c6..e61e5e9d1 100644 --- a/README.md +++ b/README.md @@ -52,19 +52,19 @@ $ java -jar ./examples/hawkbit-mgmt-api-client/target/hawkbit-mgmt-api-client-#v * The master branch contains future development towards 0.2. We are currently focusing on: * Rollout Management for large scale rollouts. * Clustering capabilities for the update server. - * Upgrade of Spring Boot and Vaadin depedencies. + * Upgrade of Spring Boot and Vaadin dependencies. * And of course tons of usability improvements and bug fixes. # Modules -`hawkbit-core` : core elements. -`hawkbit-security-core` : core security elements. -`hawkbit-security-integration` : security integration elements to integrate security into hawkbit. -`hawkbit-artifact-repository-mongo` : artifact repository implementation to mongoDB. +`hawkbit-core` : internal interfaces and utility classes.. +`hawkbit-security-core` : authentication and authorization. +`hawkbit-security-integration` : authentication and authorization integrated with the APIs. +`hawkbit-artifact-repository-mongo` : artifact repository implementation to MongoDB. `hawkbit-autoconfigure` : spring-boot auto-configuration. `hawkbit-dmf-api` : API for the Device Management Integration. `hawkbit-dmf-amqp` : AMQP endpoint implementation for the DMF API. -`hawkbit-repository` : repository implemenation based on SQL for all meta-data. +`hawkbit-repository` : repository implementation based on SQL for all meta-data. `hawkbit-http-security` : implementation for security filters for HTTP. `hawkbit-rest-api` : API classes for the REST Management API. `hawkbit-rest-resource` : HTTP REST endpoints for the Management and the Direct Device API. diff --git a/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/Start.java b/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/Start.java index 1c4c5d32d..abf2740fa 100644 --- a/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/Start.java +++ b/examples/hawkbit-custom-theme-example/src/main/java/org/eclipse/hawkbit/app/Start.java @@ -22,14 +22,17 @@ import org.springframework.context.annotation.Import; @SpringBootApplication @Import({ RepositoryApplicationConfiguration.class }) @EnableHawkbitManagedSecurityConfiguration +// Exception squid:S1118 - Spring boot standard behavior +@SuppressWarnings({ "squid:S1118" }) public class Start { - /** * Main method to start the spring-boot application. * * @param args * the VM arguments. */ + // Exception squid:S2095 - Spring boot standard behavior + @SuppressWarnings({ "squid:S2095" }) public static void main(final String[] args) { SpringApplication.run(Start.class, args); } diff --git a/examples/hawkbit-device-simulator/pom.xml b/examples/hawkbit-device-simulator/pom.xml index c74eace3e..728fe0595 100644 --- a/examples/hawkbit-device-simulator/pom.xml +++ b/examples/hawkbit-device-simulator/pom.xml @@ -1,4 +1,3 @@ - - 4.0.0 @@ -133,6 +133,10 @@ spring-boot-configuration-processor true + + org.apache.httpcomponents + httpclient + diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AbstractSimulatedDevice.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AbstractSimulatedDevice.java index 474acb6c4..890f43367 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AbstractSimulatedDevice.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/AbstractSimulatedDevice.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.simulator; +import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus; + /** * The bean of a simulated device which can be stored in the * {@link DeviceSimulatorRepository} or shown in the UI. @@ -22,16 +24,15 @@ public abstract class AbstractSimulatedDevice { private Status status; private double progress; private String swversion = "unknown"; - private ResponseStatus responseStatus = ResponseStatus.SUCCESSFUL; + private UpdateStatus updateStatus = new UpdateStatus(ResponseStatus.SUCCESSFUL, "Simulation complete!"); private Protocol protocol = Protocol.DMF_AMQP; + private String targetSecurityToken; private int nextPollCounterSec; /** * Enum definition of the protocol to be used for the simulated device. * - * @author Michael Hirsch - * */ public enum Protocol { /** @@ -69,24 +70,6 @@ public abstract class AbstractSimulatedDevice { ERROR; } - /** - * The status to response to the hawkbit update server if an simulated - * update process should be respond with successful or failure update. - * - * @author Michael Hirsch - * - */ - public enum ResponseStatus { - /** - * updated has been successful and response the successful update. - */ - SUCCESSFUL, - /** - * updated has been not successful and response the error update. - */ - ERROR; - } - /** * empty constructor. */ @@ -158,12 +141,12 @@ public abstract class AbstractSimulatedDevice { this.swversion = swversion; } - public ResponseStatus getResponseStatus() { - return responseStatus; + public UpdateStatus getUpdateStatus() { + return updateStatus; } - public void setResponseStatus(final ResponseStatus responseStatus) { - this.responseStatus = responseStatus; + public void setUpdateStatus(final UpdateStatus updateStatus) { + this.updateStatus = updateStatus; } public Protocol getProtocol() { @@ -177,4 +160,13 @@ public abstract class AbstractSimulatedDevice { public void setNextPollCounterSec(final int nextPollDelayInSec) { this.nextPollCounterSec = nextPollDelayInSec; } + + public String getTargetSecurityToken() { + return targetSecurityToken; + } + + public void setTargetSecurityToken(final String targetSecurityToken) { + this.targetSecurityToken = targetSecurityToken; + } + } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DDISimulatedDevice.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DDISimulatedDevice.java index b58d3a413..26e613dd9 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DDISimulatedDevice.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DDISimulatedDevice.java @@ -8,8 +8,6 @@ */ package org.eclipse.hawkbit.simulator; -import java.util.concurrent.ScheduledExecutorService; - import org.eclipse.hawkbit.simulator.http.ControllerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,7 +16,7 @@ import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.PathNotFoundException; /** - * @author Michael Hirsch + * A simulated device using the DDI API of the hawkBit update server. * */ public class DDISimulatedDevice extends AbstractSimulatedDevice { @@ -26,12 +24,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { private static final Logger LOGGER = LoggerFactory.getLogger(DDISimulatedDevice.class); private final int pollDelaySec; - private final ScheduledExecutorService pollthreadpool; private final ControllerResource controllerResource; + private final DeviceSimulatorUpdater deviceUpdater; + private volatile boolean removed; private volatile Long currentActionId; - private final DeviceSimulatorUpdater deviceUpdater; /** * @param id @@ -42,18 +40,14 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { * the delay of the poll interval in sec * @param controllerResource * the http controller resource - * @param pollthreadpool - * the threadpool for polling endpoint * @param deviceUpdater * the service to update devices */ public DDISimulatedDevice(final String id, final String tenant, final int pollDelaySec, - final ControllerResource controllerResource, final ScheduledExecutorService pollthreadpool, - final DeviceSimulatorUpdater deviceUpdater) { + final ControllerResource controllerResource, final DeviceSimulatorUpdater deviceUpdater) { super(id, tenant, Protocol.DDI_HTTP); this.pollDelaySec = pollDelaySec; this.controllerResource = controllerResource; - this.pollthreadpool = pollthreadpool; this.deviceUpdater = deviceUpdater; setNextPollCounterSec(pollDelaySec); } @@ -76,27 +70,12 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { final String basePollJson = controllerResource.get(getTenant(), getId()); try { final String href = JsonPath.parse(basePollJson).read("_links.deploymentBase.href"); - final long actionId = Long.parseLong(href.substring(href.lastIndexOf("/") + 1, href.indexOf("?"))); + final long actionId = Long.parseLong(href.substring(href.lastIndexOf('/') + 1, href.indexOf('?'))); if (currentActionId == null) { final String deploymentJson = controllerResource.getDeployment(getTenant(), getId(), actionId); final String swVersion = JsonPath.parse(deploymentJson).read("deployment.chunks[0].version"); currentActionId = actionId; - deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, (device, actionId1) -> { - switch (device.getResponseStatus()) { - case SUCCESSFUL: - controllerResource.postSuccessFeedback(getTenant(), getId(), - actionId1); - break; - case ERROR: - controllerResource.postErrorFeedback(getTenant(), getId(), - actionId1); - break; - default: - throw new IllegalStateException( - "simulated device has an unknown response status + " + device.getResponseStatus()); - } - currentActionId = null; - }); + startDdiUpdate(actionId, swVersion); } } catch (final PathNotFoundException e) { // href might not be in the json response, so ignore @@ -106,4 +85,21 @@ public class DDISimulatedDevice extends AbstractSimulatedDevice { } } + + private void startDdiUpdate(final long actionId, final String swVersion) { + deviceUpdater.startUpdate(getTenant(), getId(), actionId, swVersion, null, null, (device, actionId1) -> { + switch (device.getUpdateStatus().getResponseStatus()) { + case SUCCESSFUL: + controllerResource.postSuccessFeedback(getTenant(), getId(), actionId1); + break; + case ERROR: + controllerResource.postErrorFeedback(getTenant(), getId(), actionId1); + break; + default: + throw new IllegalStateException("simulated device has an unknown response status + " + + device.getUpdateStatus().getResponseStatus()); + } + currentActionId = null; + }); + } } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DMFSimulatedDevice.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DMFSimulatedDevice.java index b9fdc827c..6b79a85b8 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DMFSimulatedDevice.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DMFSimulatedDevice.java @@ -9,10 +9,7 @@ package org.eclipse.hawkbit.simulator; /** - * An simulated device using the DMF API of the hawkbit update server. - * - * @author Michael Hirsch - * + * A simulated device using the DMF API of the hawkBit update server. */ public class DMFSimulatedDevice extends AbstractSimulatedDevice { diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java index 944ba1d07..370d6af62 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulator.java @@ -21,8 +21,6 @@ import com.vaadin.spring.annotation.EnableVaadin; /** * The main-method to start the Spring-Boot application. * - * - * */ @SpringBootApplication @EnableVaadin @@ -46,6 +44,8 @@ public class DeviceSimulator { * @param args * the args */ + // Exception squid:S2095 - Spring boot standard behavior + @SuppressWarnings({ "squid:S2095" }) public static void main(final String[] args) { SpringApplication.run(DeviceSimulator.class, args); } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java index afc3a2569..e7b81b017 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/DeviceSimulatorUpdater.java @@ -8,27 +8,56 @@ */ 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.util.ArrayList; +import java.util.List; import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLContextBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.eclipse.hawkbit.dmf.json.model.Artifact; +import org.eclipse.hawkbit.dmf.json.model.SoftwareModule; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; +import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus; import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.event.InitUpdate; import org.eclipse.hawkbit.simulator.event.ProgressUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import com.google.common.eventbus.EventBus; +import com.google.common.io.BaseEncoding; +import com.google.common.io.ByteStreams; /** - * @author Michael Hirsch + * Update simulation handler. * */ @Service public class DeviceSimulatorUpdater { + private static final Logger LOGGER = LoggerFactory.getLogger(DeviceSimulatorUpdater.class); private static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(4); @@ -54,14 +83,18 @@ public class DeviceSimulatorUpdater { * @param actionId * the actionId from the hawkbit update server to start the * update. - * @param swVersion + * @param modules * the software module version from the hawkbit update server + * @param swVersion + * the software version as static value in case modules is null + * @param targetSecurityToken + * the target security token for download authentication * @param callback * the callback which gets called when the simulated update * process has been finished */ public void startUpdate(final String tenant, final String id, final long actionId, final String swVersion, - final UpdaterCallback callback) { + final List modules, final String targetSecurityToken, final UpdaterCallback callback) { AbstractSimulatedDevice device = repository.get(tenant, id); // plug and play - non existing device will be auto created @@ -70,14 +103,23 @@ public class DeviceSimulatorUpdater { } 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)); - threadPool.schedule(new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), - 2_000, TimeUnit.MILLISECONDS); + threadPool.schedule( + new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules), 2_000, + TimeUnit.MILLISECONDS); } private static final class DeviceSimulatorUpdateThread implements Runnable { + private static final int MINIMUM_TOKENLENGTH_FOR_HINT = 6; + private static final Random rndSleep = new SecureRandom(); private final AbstractSimulatedDevice device; @@ -85,38 +127,205 @@ public class DeviceSimulatorUpdater { private final long actionId; private final EventBus eventbus; private final UpdaterCallback callback; + private final List modules; private DeviceSimulatorUpdateThread(final AbstractSimulatedDevice device, final SpSenderService spSenderService, - final long actionId, final EventBus eventbus, final UpdaterCallback callback) { + final long actionId, final EventBus eventbus, final UpdaterCallback callback, + final List modules) { this.device = device; this.spSenderService = spSenderService; this.actionId = actionId; this.eventbus = eventbus; this.callback = callback; + this.modules = modules; } @Override public void run() { + if (device.getProgress() <= 0 && modules != null) { + device.setUpdateStatus(simulateDownloads(device.getTargetSecurityToken())); + if (isErrorResponse(device.getUpdateStatus())) { + callback.updateFinished(device, actionId); + eventbus.post(new ProgressUpdate(device)); + return; + } + } + final double newProgress = device.getProgress() + 0.2; device.setProgress(newProgress); if (newProgress < 1.0) { threadPool.schedule( - new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback), + new DeviceSimulatorUpdateThread(device, spSenderService, actionId, eventbus, callback, modules), rndSleep.nextInt(5_000), TimeUnit.MILLISECONDS); } else { callback.updateFinished(device, actionId); } eventbus.post(new ProgressUpdate(device)); } + + private UpdateStatus simulateDownloads(final String targetToken) { + final List status = new ArrayList<>(); + + LOGGER.info("Simulate downloads for {}", device.getId()); + + modules.forEach(module -> module.getArtifacts() + .forEach(artifact -> handleArtifacts(targetToken, status, artifact))); + + final UpdateStatus result = new UpdateStatus(ResponseStatus.SUCCESSFUL); + result.getStatusMessages().add("Simulation complete!"); + status.forEach(download -> { + result.getStatusMessages().addAll(download.getStatusMessages()); + if (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 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 ""; + } + + 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 * been finished and the caller of starting the simulated update process can - * send the result to the hawkbit update server back. - * - * @author Michael Hirsch - * + * send the result back to the hawkBit update server. */ @FunctionalInterface public interface UpdaterCallback { diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/NextPollTimeController.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/NextPollTimeController.java index 9c78ec65a..956d6d36a 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/NextPollTimeController.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/NextPollTimeController.java @@ -26,9 +26,6 @@ import com.google.common.eventbus.EventBus; /** * Poll time trigger which executes the {@link DDISimulatedDevice#poll()} every * second. - * - * @author Michael Hirsch - * */ @Component public class NextPollTimeController { @@ -59,16 +56,15 @@ public class NextPollTimeController { devices.forEach(device -> { int nextCounter = device.getNextPollCounterSec() - 1; - if (nextCounter < 0) { - if (device instanceof DDISimulatedDevice) { - try { - pollService.submit(() -> ((DDISimulatedDevice) device).poll()); - } catch (final IllegalStateException e) { - LOGGER.trace("Device could not be polled", e); - } - nextCounter = ((DDISimulatedDevice) device).getPollDelaySec(); + if (nextCounter < 0 && device instanceof DDISimulatedDevice) { + try { + pollService.submit(() -> ((DDISimulatedDevice) device).poll()); + } catch (final IllegalStateException e) { + LOGGER.trace("Device could not be polled", e); } + nextCounter = ((DDISimulatedDevice) device).getPollDelaySec(); } + device.setNextPollCounterSec(nextCounter); }); eventBus.post(new NextPollCounterUpdate(devices)); diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java index d3e080806..f29aad001 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/SimulatedDeviceFactory.java @@ -9,8 +9,6 @@ package org.eclipse.hawkbit.simulator; import java.net.URL; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; import org.eclipse.hawkbit.simulator.http.ControllerResource; @@ -24,15 +22,9 @@ import feign.Logger; /** * The simulated device factory to create either {@link DMFSimulatedDevice} or * {@link DDISimulatedDevice#}. - * - * @author Michael Hirsch - * */ @Service public class SimulatedDeviceFactory { - - private static final ScheduledExecutorService pollThreadPool = Executors.newScheduledThreadPool(4); - @Autowired private DeviceSimulatorUpdater deviceUpdater; @@ -47,7 +39,8 @@ public class SimulatedDeviceFactory { * the protocol of the device * @return the created simulated device */ - public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, final Protocol protocol) { + public AbstractSimulatedDevice createSimulatedDevice(final String id, final String tenant, + final Protocol protocol) { return createSimulatedDevice(id, tenant, protocol, 30, null, null); } @@ -80,7 +73,7 @@ public class SimulatedDeviceFactory { final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger()) .requestInterceptor(new GatewayTokenInterceptor(gatewayToken)).logLevel(Logger.Level.BASIC) .target(ControllerResource.class, baseEndpoint.toString()); - return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, pollThreadPool, deviceUpdater); + return new DDISimulatedDevice(id, tenant, pollDelaySec, controllerResource, deviceUpdater); default: throw new IllegalArgumentException("Protocol " + protocol + " unknown"); } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java new file mode 100644 index 000000000..f4e1f75a7 --- /dev/null +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/UpdateStatus.java @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.simulator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Update status of the simulated update. + * + */ +public class UpdateStatus { + private ResponseStatus responseStatus; + private List statusMessages; + + /** + * Constructor. + * + * @param responseStatus + * of the update + */ + public UpdateStatus(final ResponseStatus responseStatus) { + this.responseStatus = responseStatus; + } + + /** + * Constructor including status message. + * + * @param responseStatus + * of the update + * @param message + * of the update status + */ + public UpdateStatus(final ResponseStatus responseStatus, final String message) { + this(responseStatus); + statusMessages = new ArrayList<>(); + statusMessages.add(message); + } + + public ResponseStatus getResponseStatus() { + return responseStatus; + } + + public void setResponseStatus(final ResponseStatus responseStatus) { + this.responseStatus = responseStatus; + } + + public List 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; + } + +} \ No newline at end of file diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java index f22839422..e06b2baf3 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpReceiverService.java @@ -25,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; +import com.google.common.collect.Lists; + /** * Handle all incoming Messages from hawkBit update server. * @@ -88,6 +90,8 @@ public class SpReceiverService extends ReceiverService { if (eventHeader == null) { logAndThrowMessageError(message, "Event Topic is not set"); } + // Exception squid:S2259 - Checked before + @SuppressWarnings({ "squid:S2259" }) final EventTopic eventTopic = EventTopic.valueOf(eventHeader.toString()); switch (eventTopic) { case DOWNLOAD_AND_INSTALL: @@ -109,7 +113,7 @@ public class SpReceiverService extends ReceiverService { final Long actionId = convertMessage(message, Long.class); final SimulatedUpdate update = new SimulatedUpdate(tenant, thingId, actionId); - spSenderService.finishUpdateProcess(update, "Simulation canceled"); + spSenderService.finishUpdateProcess(update, Lists.newArrayList("Simulation canceled")); } private void handleUpdateProcess(final Message message, final String thingId) { @@ -120,19 +124,20 @@ public class SpReceiverService extends ReceiverService { final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(message, DownloadAndUpdateRequest.class); final Long actionId = downloadAndUpdateRequest.getActionId(); + final String targetSecurityToken = downloadAndUpdateRequest.getTargetSecurityToken(); - deviceUpdater.startUpdate(tenant, thingId, actionId, - downloadAndUpdateRequest.getSoftwareModules().get(0).getModuleVersion(), (device, actionId1) -> { - switch (device.getResponseStatus()) { + deviceUpdater.startUpdate(tenant, thingId, actionId, null, downloadAndUpdateRequest.getSoftwareModules(), + targetSecurityToken, (device, actionId1) -> { + switch (device.getUpdateStatus().getResponseStatus()) { case SUCCESSFUL: spSenderService.finishUpdateProcess( new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), - "Simulation complete!"); + device.getUpdateStatus().getStatusMessages()); break; case ERROR: spSenderService.finishUpdateProcessWithError( new SimulatedUpdate(device.getTenant(), device.getId(), actionId1), - "Simulation complete with error!"); + device.getUpdateStatus().getStatusMessages()); break; default: break; diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java index 2358bf013..1ced8c2fd 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/SpSenderService.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.simulator.amqp; +import java.util.List; import java.util.Map; import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings; @@ -23,13 +24,9 @@ import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; /** - * Sender service to send message to SP. - * - * - * + * Sender service to send messages to update server. */ @Service public class SpSenderService extends SenderService { @@ -59,8 +56,9 @@ public class SpSenderService extends SenderService { * @param description * a description according the update process */ - public void finishUpdateProcess(final SimulatedUpdate update, final String description) { - final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED, description); + public void finishUpdateProcess(final SimulatedUpdate update, final List updateResultMessages) { + final Message updateResultMessage = createUpdateResultMessage(update, ActionStatus.FINISHED, + updateResultMessages); sendMessage(spExchange, updateResultMessage); } @@ -72,9 +70,9 @@ public class SpSenderService extends SenderService { * @param messageDescription * a description according the update process */ - public void finishUpdateProcessWithError(final SimulatedUpdate update, final String messageDescription) { - sendErrorgMessage(update, messageDescription); - LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", messageDescription, + public void finishUpdateProcessWithError(final SimulatedUpdate update, final List updateResultMessages) { + sendErrorgMessage(update, updateResultMessages); + LOGGER.debug("Update process finished with error \"{}\" reported by thing {}", updateResultMessages, update.getThingId()); } @@ -88,8 +86,8 @@ public class SpSenderService extends SenderService { * @param actionId * the ID of the action for the error message */ - public void sendErrorMessage(final String tenant, final String messageDescription, final Long actionId) { - final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, messageDescription, actionId); + public void sendErrorMessage(final String tenant, final List updateResultMessages, final Long actionId) { + final Message message = createActionStatusMessage(tenant, ActionStatus.ERROR, updateResultMessages, actionId); sendMessage(spExchange, message); } @@ -101,8 +99,8 @@ public class SpSenderService extends SenderService { * @param warningMessage * a warning description */ - public void sendWarningMessage(final SimulatedUpdate update, final String warningMessage) { - final Message message = createActionStatusMessage(update, warningMessage, ActionStatus.WARNING); + public void sendWarningMessage(final SimulatedUpdate update, final List updateResultMessages) { + final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.WARNING); sendMessage(spExchange, message); } @@ -119,8 +117,8 @@ public class SpSenderService extends SenderService { * the cached value */ public void sendActionStatusMessage(final String tenant, final ActionStatus actionStatus, - final String actionMessage, final Long actionId) { - final Message message = createActionStatusMessage(tenant, actionStatus, actionMessage, actionId); + final List updateResultMessages, final Long actionId) { + final Message message = createActionStatusMessage(tenant, actionStatus, updateResultMessages, actionId); sendMessage(message); } @@ -162,11 +160,11 @@ public class SpSenderService extends SenderService { * * @param context * the current context - * @param messageDescription - * a description according the update process + * @param updateResultMessages + * a list of descriptions according the update process */ - private void sendErrorgMessage(final SimulatedUpdate update, final String messageDescription) { - final Message message = createActionStatusMessage(update, messageDescription, ActionStatus.ERROR); + private void sendErrorgMessage(final SimulatedUpdate update, final List updateResultMessages) { + final Message message = createActionStatusMessage(update, updateResultMessages, ActionStatus.ERROR); sendMessage(spExchange, message); } @@ -183,7 +181,7 @@ public class SpSenderService extends SenderService { * the cacheValue value */ private Message createActionStatusMessage(final String tenant, final ActionStatus actionStatus, - final String actionMessage, final Long actionId) { + final List updateResultMessages, final Long actionId) { final MessageProperties messageProperties = new MessageProperties(); final Map headers = messageProperties.getHeaders(); final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); @@ -192,15 +190,14 @@ public class SpSenderService extends SenderService { headers.put(MessageHeaderKey.TENANT, tenant); headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON); - if (!StringUtils.isEmpty(actionMessage)) { - actionUpdateStatus.getMessage().add(actionMessage); - } + actionUpdateStatus.getMessage().addAll(updateResultMessages); + actionUpdateStatus.setActionId(actionId); return convertMessage(actionUpdateStatus, messageProperties); } private Message createUpdateResultMessage(final SimulatedUpdate cacheValue, final ActionStatus actionStatus, - final String updateResultMessage) { + final List updateResultMessages) { final MessageProperties messageProperties = new MessageProperties(); final Map headers = messageProperties.getHeaders(); final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); @@ -209,14 +206,14 @@ public class SpSenderService extends SenderService { headers.put(MessageHeaderKey.TENANT, cacheValue.getTenant()); headers.put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); headers.put(MessageHeaderKey.CONTENT_TYPE, MessageProperties.CONTENT_TYPE_JSON); - actionUpdateStatus.getMessage().add(updateResultMessage); + actionUpdateStatus.getMessage().addAll(updateResultMessages); actionUpdateStatus.setActionId(cacheValue.getActionId()); return convertMessage(actionUpdateStatus, messageProperties); } - private Message createActionStatusMessage(final SimulatedUpdate update, final String messageDescription, + private Message createActionStatusMessage(final SimulatedUpdate update, final List updateResultMessages, final ActionStatus status) { - return createActionStatusMessage(update.getTenant(), status, messageDescription, update.getActionId()); + return createActionStatusMessage(update.getTenant(), status, updateResultMessages, update.getActionId()); } } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/ProgressUpdate.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/ProgressUpdate.java index 3e34a0fa1..6c18e61ac 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/ProgressUpdate.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/event/ProgressUpdate.java @@ -13,8 +13,6 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice; /** * Event definition object which is published if the simulated device updated * its update progress. - * - * @author Michael Hirsch * */ public class ProgressUpdate { diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorView.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorView.java index 28ad0eaa9..bd6ecbe8b 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorView.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/ui/SimulatorView.java @@ -8,21 +8,19 @@ */ package org.eclipse.hawkbit.simulator.ui; -import java.net.URL; import java.util.List; import java.util.Locale; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol; -import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.ResponseStatus; import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Status; import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository; import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory; +import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus; import org.eclipse.hawkbit.simulator.amqp.SpSenderService; import org.eclipse.hawkbit.simulator.event.InitUpdate; import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate; import org.eclipse.hawkbit.simulator.event.ProgressUpdate; -import org.eclipse.hawkbit.simulator.ui.GenerateDialog.GenerateDialogCallback; import org.springframework.beans.factory.annotation.Autowired; import com.google.common.collect.Lists; @@ -52,13 +50,27 @@ import com.vaadin.ui.renderers.ProgressBarRenderer; * Vaadin view which allows to generate devices through the DMF API and show the * current simulated devices in a grid with their current status and update * progress. - * - * @author Michael Hirsch * */ @SpringView(name = "") public class SimulatorView extends VerticalLayout implements View { + private static final String NEXT_POLL_COUNTER_SEC_COL = "nextPollCounterSec"; + + private static final String RESPONSE_STATUS_COL = "responseStatus"; + + private static final String PROTOCOL_COL = "protocol"; + + private static final String TENANT_COL = "tenant"; + + private static final String PROGRESS_COL = "progress"; + + private static final String SWVERSION_COL = "swversion"; + + private static final String STATUS_COL = "status"; + + private static final String ID_COL = "id"; + private static final long serialVersionUID = 1L; @Autowired @@ -79,6 +91,7 @@ public class SimulatorView extends VerticalLayout implements View { private BeanContainer beanContainer; + @SuppressWarnings("unchecked") @Override public void enter(final ViewChangeEvent event) { eventbus.register(this); @@ -91,7 +104,7 @@ public class SimulatorView extends VerticalLayout implements View { createToolbar(); beanContainer = new BeanContainer<>(AbstractSimulatedDevice.class); - beanContainer.setBeanIdProperty("id"); + beanContainer.setBeanIdProperty(ID_COL); grid.setSizeFull(); grid.setCellStyleGenerator(new CellStyleGenerator() { @@ -100,28 +113,28 @@ public class SimulatorView extends VerticalLayout implements View { @Override public String getStyle(final CellReference cellReference) { - return cellReference.getPropertyId().equals("status") ? "centeralign" : null; + return cellReference.getPropertyId().equals(STATUS_COL) ? "centeralign" : null; } }); grid.setSelectionMode(SelectionMode.NONE); grid.setContainerDataSource(beanContainer); - grid.appendHeaderRow().getCell("responseStatus").setComponent(responseComboBox); - grid.setColumnOrder("id", "status", "swversion", "progress", "tenant", "protocol", "responseStatus", - "nextPollCounterSec"); + grid.appendHeaderRow().getCell(RESPONSE_STATUS_COL).setComponent(responseComboBox); + grid.setColumnOrder(ID_COL, STATUS_COL, SWVERSION_COL, PROGRESS_COL, TENANT_COL, PROTOCOL_COL, + RESPONSE_STATUS_COL, NEXT_POLL_COUNTER_SEC_COL); // header widths - grid.getColumn("status").setMaximumWidth(80); - grid.getColumn("protocol").setMaximumWidth(180); - grid.getColumn("responseStatus").setMaximumWidth(240); - grid.getColumn("nextPollCounterSec").setMaximumWidth(210); + grid.getColumn(STATUS_COL).setMaximumWidth(80); + grid.getColumn(PROTOCOL_COL).setMaximumWidth(180); + grid.getColumn(RESPONSE_STATUS_COL).setMaximumWidth(240); + grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).setMaximumWidth(210); - grid.getColumn("nextPollCounterSec").setHeaderCaption("Next Poll in (sec)"); - grid.getColumn("swversion").setHeaderCaption("SW Version"); - grid.getColumn("responseStatus").setHeaderCaption("Response Update Status"); - grid.getColumn("progress").setRenderer(new ProgressBarRenderer()); - grid.getColumn("protocol").setConverter(createProtocolConverter()); - grid.getColumn("status").setRenderer(new HtmlRenderer(), createStatusConverter()); - grid.removeColumn("tenant"); + grid.getColumn(NEXT_POLL_COUNTER_SEC_COL).setHeaderCaption("Next Poll in (sec)"); + grid.getColumn(SWVERSION_COL).setHeaderCaption("SW Version"); + grid.getColumn(RESPONSE_STATUS_COL).setHeaderCaption("Response Update Status"); + grid.getColumn(PROGRESS_COL).setRenderer(new ProgressBarRenderer()); + grid.getColumn(PROTOCOL_COL).setConverter(createProtocolConverter()); + grid.getColumn(STATUS_COL).setRenderer(new HtmlRenderer(), createStatusConverter()); + grid.removeColumn(TENANT_COL); // grid combobox responseComboBox.setItemIcon(ResponseStatus.SUCCESSFUL, FontAwesome.CHECK_CIRCLE); @@ -129,8 +142,8 @@ public class SimulatorView extends VerticalLayout implements View { responseComboBox.setNullSelectionAllowed(false); responseComboBox.setValue(ResponseStatus.SUCCESSFUL); responseComboBox.addValueChangeListener(valueChangeEvent -> { - beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId).getItemProperty("responseStatus") - .setValue(valueChangeEvent.getProperty().getValue())); + beanContainer.getItemIds().forEach(itemId -> beanContainer.getItem(itemId) + .getItemProperty(RESPONSE_STATUS_COL).setValue(valueChangeEvent.getProperty().getValue())); }); // add all components @@ -141,7 +154,7 @@ public class SimulatorView extends VerticalLayout implements View { setExpandRatio(grid, 1.0F); // load beans - repository.getAll().forEach(device -> beanContainer.addBean(device)); + repository.getAll().forEach(beanContainer::addBean); } @Override @@ -150,21 +163,16 @@ public class SimulatorView extends VerticalLayout implements View { eventbus.unregister(this); } + @SuppressWarnings("unchecked") @Subscribe public void pollCounterUpdate(final NextPollCounterUpdate update) { final List devices = update.getDevices(); - this.getUI().access(new Runnable() { - - @Override - public void run() { - devices.forEach(device -> { - final BeanItem item = beanContainer.getItem(device.getId()); - if (item != null) { - item.getItemProperty("nextPollCounterSec").setValue(device.getNextPollCounterSec()); - } - }); + this.getUI().access(() -> devices.forEach(device -> { + final BeanItem item = beanContainer.getItem(device.getId()); + if (item != null) { + item.getItemProperty(NEXT_POLL_COUNTER_SEC_COL).setValue(device.getNextPollCounterSec()); } - }); + })); } /** @@ -173,21 +181,19 @@ public class SimulatorView extends VerticalLayout implements View { * @param update * the update event posted on the event bus */ + @SuppressWarnings("unchecked") @Subscribe public void initUpdate(final InitUpdate update) { final AbstractSimulatedDevice device = update.getDevice(); - this.getUI().access(new Runnable() { - - @Override - public void run() { - final BeanItem item = beanContainer.getItem(device.getId()); - if (item != null) { - item.getItemProperty("progress").setValue(device.getProgress()); - item.getItemProperty("status").setValue(Status.PEDNING); - item.getItemProperty("swversion").setValue(device.getSwversion()); - } - + this.getUI().access(() -> { + final BeanItem item = beanContainer.getItem(device.getId()); + if (item == null) { + return; } + + 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 * the update event posted on the event bus */ + @SuppressWarnings("unchecked") @Subscribe public void progessUpdate(final ProgressUpdate update) { final AbstractSimulatedDevice device = update.getDevice(); - this.getUI().access(new Runnable() { - @Override - public void run() { - final BeanItem item = beanContainer.getItem(device.getId()); - if (item != null) { - item.getItemProperty("progress").setValue(device.getProgress()); - if (device.getProgress() >= 1) { - switch (device.getResponseStatus()) { - case SUCCESSFUL: - item.getItemProperty("status").setValue(Status.FINISH); - break; - case ERROR: - item.getItemProperty("status").setValue(Status.ERROR); - break; - default: - item.getItemProperty("status").setValue(Status.UNKNWON); - } - } else { - item.getItemProperty("status").setValue(Status.PEDNING); - } - } - + this.getUI().access(() -> { + final BeanItem item = beanContainer.getItem(device.getId()); + if (item != null) { + item.getItemProperty(PROGRESS_COL).setValue(device.getProgress()); + setStatusColumn(device, item); } }); } + @SuppressWarnings("unchecked") + private void setStatusColumn(final AbstractSimulatedDevice device, final BeanItem item) { + if (device.getProgress() >= 1) { + switch (device.getUpdateStatus().getResponseStatus()) { + case SUCCESSFUL: + item.getItemProperty(STATUS_COL).setValue(Status.FINISH); + break; + case ERROR: + item.getItemProperty(STATUS_COL).setValue(Status.ERROR); + break; + default: + item.getItemProperty(STATUS_COL).setValue(Status.UNKNWON); + } + } else { + item.getItemProperty(STATUS_COL).setValue(Status.PEDNING); + } + } + private void createToolbar() { final Button createDevicesButton = new Button("generate..."); createDevicesButton.setIcon(FontAwesome.GEARS); @@ -246,18 +254,15 @@ public class SimulatorView extends VerticalLayout implements View { } private void openGenerateDialog() { - UI.getCurrent().addWindow(new GenerateDialog(new GenerateDialogCallback() { - @Override - public void okButton(final String namePrefix, final String tenant, final int amount, final int pollDelay, - final URL basePollUrl, final String gatewayToken, final Protocol protocol) { - for (int index = 0; index < amount; index++) { - final String deviceId = namePrefix + index; - beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId, - tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken))); - spSenderService.createOrUpdateThing(tenant, deviceId); - } - } - })); + UI.getCurrent().addWindow( + new GenerateDialog((namePrefix, tenant, amount, pollDelay, basePollUrl, gatewayToken, protocol) -> { + for (int index = 0; index < amount; index++) { + final String deviceId = namePrefix + index; + beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId, + tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken))); + spSenderService.createOrUpdateThing(tenant, deviceId); + } + })); } private Converter createProtocolConverter() { diff --git a/examples/hawkbit-example-app/README.md b/examples/hawkbit-example-app/README.md index ecbec93c3..068acdd15 100644 --- a/examples/hawkbit-example-app/README.md +++ b/examples/hawkbit-example-app/README.md @@ -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. ## 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 API https://hawkbit.eu-gb.mybluemix.net/rest/v1/targets (don't forget basic auth header) -- try out DDI API https://hawkbit.eu-gb.mybluemix.net/DEFAULT/controller/v1/MYTESTDEVICE +- 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; username: admin, passwd: admin) +- try out DDI API https://hawkbit.eu-gb.mybluemix.net/DEFAULT/controller/v1/MYTESTDEVICE (authentication disabled) ## On your own workstation ### Run ``` 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: + ``` run org eclipse.hawkbit.app.Start ``` diff --git a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyLoginUI.java b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyLoginUI.java index 763e8447e..d8c5c8493 100644 --- a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyLoginUI.java +++ b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyLoginUI.java @@ -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 * the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in * this example to the defined {@link 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 { private static final long serialVersionUID = 1L; diff --git a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java index 68d3b2fd9..e5bc7535d 100644 --- a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java +++ b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/MyUI.java @@ -29,6 +29,9 @@ import com.vaadin.spring.annotation.SpringUI; */ @SpringUI @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 { private static final long serialVersionUID = 1L; diff --git a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/Start.java b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/Start.java index a517dbb08..b08ae50d8 100644 --- a/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/Start.java +++ b/examples/hawkbit-example-app/src/main/java/org/eclipse/hawkbit/app/Start.java @@ -26,6 +26,8 @@ import org.springframework.context.annotation.Import; @EnableHawkbitManagedSecurityConfiguration @EnableRestResources @EnableDirectDeviceApi +// Exception squid:S1118 - Spring boot standard behavior +@SuppressWarnings({ "squid:S1118" }) public class Start { /** @@ -34,6 +36,8 @@ public class Start { * @param args * the VM arguments. */ + // Exception squid:S2095 - Spring boot standard behavior + @SuppressWarnings({ "squid:S2095" }) public static void main(final String[] args) { SpringApplication.run(Start.class, args); } diff --git a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties index ecf71da41..a0cad4e9b 100644 --- a/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties +++ b/examples/hawkbit-example-app/src/main/resources/application-cloudsandbox.properties @@ -8,3 +8,9 @@ # vaadin.servlet.productionMode=true + +hawkbit.artifact.url.coap.enabled=false +hawkbit.artifact.url.http.enabled=false +hawkbit.artifact.url.https.enabled=true +hawkbit.artifact.url.https.pattern={protocol}://{hostname}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} +hawkbit.artifact.url.https.hostname=hawkbit.eu-gb.mybluemix.net \ No newline at end of file diff --git a/examples/hawkbit-example-app/src/main/resources/application-mysql.properties b/examples/hawkbit-example-app/src/main/resources/application-mysql.properties new file mode 100644 index 000000000..202500245 --- /dev/null +++ b/examples/hawkbit-example-app/src/main/resources/application-mysql.properties @@ -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 diff --git a/examples/hawkbit-example-app/src/main/resources/application.properties b/examples/hawkbit-example-app/src/main/resources/application.properties index 64661d2ec..6e05b6b5a 100644 --- a/examples/hawkbit-example-app/src/main/resources/application.properties +++ b/examples/hawkbit-example-app/src/main/resources/application.properties @@ -7,15 +7,22 @@ # http://www.eclipse.org/legal/epl-v10.html # +# DDI authentication configuration hawkbit.server.ddi.security.authentication.anonymous.enabled=true -hawkbit.server.ddi.security.authentication.targettoken.enabled=false -hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false +hawkbit.server.ddi.security.authentication.targettoken.enabled=true +hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=true -spring.profiles.active=amqp +# Download URL generation config +hawkbit.artifact.url.coap.enabled=false +hawkbit.artifact.url.http.enabled=true +hawkbit.artifact.url.http.port=8080 +hawkbit.artifact.url.https.enabled=false +## Vaadin configuration vaadin.servlet.productionMode=false -## Configuration for RabbitMQ integration +## Configuration for DMF/RabbitMQ integration +spring.profiles.active=amqp spring.rabbitmq.username=guest spring.rabbitmq.password=guest spring.rabbitmq.virtualHost=/ diff --git a/examples/hawkbit-mgmt-api-client/pom.xml b/examples/hawkbit-mgmt-api-client/pom.xml index 9aaf53dc6..77e35df83 100644 --- a/examples/hawkbit-mgmt-api-client/pom.xml +++ b/examples/hawkbit-mgmt-api-client/pom.xml @@ -18,7 +18,7 @@ jar hawkbit-mgmt-api-client - hawkBit Management API example client + hawkBit :: Management API example client diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java index 358cff0db..01acdac72 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetBuilder.java @@ -18,8 +18,9 @@ import com.google.common.collect.Lists; /** * Builder pattern for building {@link DistributionSetRequestBodyPost}. */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class DistributionSetBuilder { - private String name; private String version; private String type; diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java index 752834c7d..ff03bb442 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/DistributionSetTypeBuilder.java @@ -21,8 +21,9 @@ import com.google.common.collect.Lists; * Builder pattern for building {@link DistributionSetTypeRequestBodyPost}. * */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class DistributionSetTypeBuilder { - private String key; private String name; private final List mandatorymodules = Lists.newArrayList(); diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java index 2e01e0ba2..e9203fc39 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java @@ -17,6 +17,8 @@ import org.eclipse.hawkbit.rest.resource.model.rollout.RolloutRestRequestBody; * Builder pattern for building {@link RolloutRestRequestBody}. * */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class RolloutBuilder { private String name; diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java index 4bbfd92b4..169a159d0 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleBuilder.java @@ -21,6 +21,8 @@ import com.google.common.collect.Lists; * Builder pattern for building {@link SoftwareModuleRequestBodyPost}. * */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class SoftwareModuleBuilder { private String name; diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java index a6472f0a0..e27cedc72 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/SoftwareModuleTypeBuilder.java @@ -21,6 +21,8 @@ import com.google.common.collect.Lists; * Builder pattern for building {@link SoftwareModuleRequestBodyPost}. * */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class SoftwareModuleTypeBuilder { private String key; diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java index 6f2eb3248..32f7c1107 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TagBuilder.java @@ -19,6 +19,8 @@ import com.google.common.collect.Lists; * Builder pattern for building {@link TagRequestBodyPut}. * */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class TagBuilder { private String name; diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java index e496407e1..aba1188dc 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java @@ -21,6 +21,8 @@ import com.google.common.collect.Lists; * Builder pattern for building {@link TargetRequestBody}. * */ +// Exception squid:S1701 - builder pattern +@SuppressWarnings({ "squid:S1701" }) public class TargetBuilder { private String controllerId; diff --git a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java index 6981834b4..5f12498ff 100644 --- a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java +++ b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/ArtifactStore.java @@ -8,11 +8,14 @@ */ package org.eclipse.hawkbit.artifact.repository; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.security.DigestOutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -122,7 +125,11 @@ public class ArtifactStore implements ArtifactRepository { LOGGER.debug("storing file {} of content {}", filename, contentType); tempFile = File.createTempFile("uploadFile", null); 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) { 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 GridFsArtifact storedArtifact; try { @@ -185,7 +192,8 @@ public class ArtifactStore implements ArtifactRepository { 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() + " not matching the calculated md5 hash " + storedArtifact.getHashes().getMd5(), HashNotMatchException.MD5); @@ -195,14 +203,14 @@ public class ArtifactStore implements ArtifactRepository { } - private static String computeSHA1Hash(final InputStream stream, final FileOutputStream os, - final String providedSHA1Sum) throws NoSuchAlgorithmException, IOException { + private static String computeSHA1Hash(final InputStream stream, final OutputStream os, final String providedSHA1Sum) + throws NoSuchAlgorithmException, IOException { String sha1Hash; // compute digest final MessageDigest md = MessageDigest.getInstance("SHA-1"); - final DigestOutputStream dos = new DigestOutputStream(os, md); - ByteStreams.copy(stream, dos); - dos.close(); + try (final DigestOutputStream dos = new DigestOutputStream(os, md)) { + ByteStreams.copy(stream, dos); + } sha1Hash = BaseEncoding.base16().lowerCase().encode(md.digest()); if (providedSHA1Sum != null && !providedSHA1Sum.equalsIgnoreCase(sha1Hash)) { throw new HashNotMatchException( diff --git a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java index 02fb22725..e01c6a455 100644 --- a/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java +++ b/hawkbit-artifact-repository-mongo/src/main/java/org/eclipse/hawkbit/artifact/repository/MongoConfiguration.java @@ -71,6 +71,8 @@ public class MongoConfiguration extends AbstractMongoConfiguration { @Override @Bean @ConditionalOnMissingBean + // Closed by pre-destroy + @SuppressWarnings({ "squid:S2095" }) public Mongo mongo() throws UnknownHostException { final MongoClientURI uri = new MongoClientURI(properties.getUri(), createBuilderOutOfOptions(options)); diff --git a/hawkbit-core/README.md b/hawkbit-core/README.md new file mode 100644 index 000000000..bf75314d1 --- /dev/null +++ b/hawkbit-core/README.md @@ -0,0 +1,3 @@ +# hawkBit Core + +Various internal interfaces and utility classes. \ No newline at end of file diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/DistributedResourceBundleMessageSource.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/DistributedResourceBundleMessageSource.java index 0b0847652..0f5301c40 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/DistributedResourceBundleMessageSource.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/DistributedResourceBundleMessageSource.java @@ -22,11 +22,10 @@ import org.springframework.core.io.support.ResourcePatternResolver; * This resource bundles using specified basenames, to resource loading. This * MessageSource implementation supports more than 1 properties file with the * same name. All properties files will be merged. - * - * - * */ 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 String PROPERTIES_SUFFIX = ".properties"; private ResourceLoader resourceLoader; diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java index 522444961..03492122c 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java @@ -13,7 +13,6 @@ package org.eclipse.hawkbit.api; * URLs to specific artifacts. * */ -@FunctionalInterface public interface ArtifactUrlHandler { /** @@ -34,4 +33,11 @@ public interface ArtifactUrlHandler { */ String getUrl(String controllerId, final Long softwareModuleId, final String filename, final String sha1Hash, final UrlProtocol protocol); + + /** + * @param protocol + * to check support for + * @return true of the handler supports given protocol. + */ + boolean protocolSupported(UrlProtocol protocol); } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java index 33fe8651e..50f3f4cad 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java @@ -78,6 +78,12 @@ public class ArtifactUrlHandlerProperties { * @return the pattern to build the URL. */ String getPattern(); + + /** + * @return true if the {@link ProtocolProperties} is + * enabled. + */ + boolean isEnabled(); } /** @@ -93,6 +99,20 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; + /** + * Enables HTTP URI generation in DDI and DMF. + */ + private boolean enabled = true; + + @Override + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + @Override public String getHostname() { return hostname; @@ -143,6 +163,20 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; + /** + * Enables HTTPS URI generation in DDI and DMF. + */ + private boolean enabled = true; + + @Override + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + @Override public String getHostname() { return hostname; @@ -193,6 +227,20 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}"; + /** + * Enables CoAP URI generation in DMF. + */ + private boolean enabled = true; + + @Override + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + @Override public String getHostname() { return hostname; diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java index 174086613..0072f2fbd 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java @@ -84,4 +84,15 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { return replaceMap; } + @Override + public boolean protocolSupported(final UrlProtocol protocol) { + final String protocolString = protocol.name().toLowerCase(); + final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString); + if (properties == null || properties.getPattern() == null) { + return false; + } + + return properties.isEnabled(); + } + } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/validator/TenantConfigurationPollingDurationValidator.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/validator/TenantConfigurationPollingDurationValidator.java index 11c9666e8..376ba8877 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/validator/TenantConfigurationPollingDurationValidator.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/validator/TenantConfigurationPollingDurationValidator.java @@ -39,6 +39,8 @@ public class TenantConfigurationPollingDurationValidator implements TenantConfig } @Override + // Exception squid:S1166 - Hide origin exception + @SuppressWarnings({ "squid:S1166" }) public void validate(final Object tenantConfigurationObject) { TenantConfigurationValidator.super.validate(tenantConfigurationObject); final String tenantConfigurationString = (String) tenantConfigurationObject; diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java index 9d120c17b..91d07de37 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java @@ -17,7 +17,6 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.security.CoapAnonymousPreAuthenticatedFilter; import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter; import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousDownload; import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousFilter; @@ -97,7 +96,6 @@ public class AmqpControllerAuthentfication { filterChain.add(anonymousDownloadFilter); filterChain.add(new ControllerPreAuthenticatedAnonymousFilter(ddiSecruityProperties)); - filterChain.add(new CoapAnonymousPreAuthenticatedFilter()); } /** diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java index 19e0cbadf..dae5772e6 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java @@ -82,6 +82,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { .getSoftwareModules(); final DownloadAndUpdateRequest downloadAndUpdateRequest = new DownloadAndUpdateRequest(); downloadAndUpdateRequest.setActionId(targetAssignDistributionSetEvent.getActionId()); + downloadAndUpdateRequest.setTargetSecurityToken(targetAssignDistributionSetEvent.getTargetToken()); for (final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule : modules) { final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(controllerId, softwareModule); @@ -154,18 +155,26 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) { final Artifact artifact = new Artifact(); - artifact.getUrls().put(Artifact.UrlProtocol.COAP, - artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), - localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP)); - artifact.getUrls().put(Artifact.UrlProtocol.HTTP, - artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), - localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP)); - artifact.getUrls().put(Artifact.UrlProtocol.HTTPS, - artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), - localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS)); + if (artifactUrlHandler.protocolSupported(UrlProtocol.COAP)) { + artifact.getUrls().put(Artifact.UrlProtocol.COAP, + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP)); + } + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTP)) { + artifact.getUrls().put(Artifact.UrlProtocol.HTTP, + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP)); + } + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTPS)) { + artifact.getUrls().put(Artifact.UrlProtocol.HTTPS, + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS)); + } artifact.setFilename(localArtifact.getFilename()); - artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), null)); + artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), localArtifact.getMd5Hash())); artifact.setSize(localArtifact.getSize()); return artifact; } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java index 447a8ffca..f26d7f3f7 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java @@ -305,7 +305,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService { final List softwareModuleList = controllerManagement .findSoftwareModulesByDistributionSet(distributionSet); eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), - target.getControllerId(), action.getId(), softwareModuleList, target.getTargetInfo().getAddress())); + target.getControllerId(), action.getId(), softwareModuleList, target.getTargetInfo().getAddress(), + target.getSecurityToken())); } @@ -336,9 +337,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService { final Action action = checkActionExist(message, actionUpdateStatus); final ActionStatus actionStatus = new ActionStatus(); - final List messageText = actionUpdateStatus.getMessage(); - final String messageString = String.join(", ", messageText); - actionStatus.addMessage(messageString); + actionUpdateStatus.getMessage().forEach(actionStatus::addMessage); + actionStatus.setAction(action); actionStatus.setOccurredAt(System.currentTimeMillis()); diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java index f2c3d254c..c5cea9e05 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java @@ -8,8 +8,8 @@ */ package org.eclipse.hawkbit.amqp; +import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -23,6 +23,7 @@ import static org.mockito.Mockito.when; import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.TestDataUtil; @@ -58,6 +59,12 @@ import ru.yandex.qatools.allure.annotations.Stories; @Stories("AmqpMessage Dispatcher Service Test") public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWithMongoDB { + private static final String TENANT = "default"; + + private static final URI AMQP_URI = IpUtil.createAmqpUri("vHost", "mytest"); + + private static final String TEST_TOKEN = "testToken"; + private AmqpMessageDispatcherService amqpMessageDispatcherService; private RabbitTemplate rabbitTemplate; @@ -89,8 +96,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit @Description("Verfies that download and install event with no software modul works") public void testSendDownloadRequesWithEmptySoftwareModules() { final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( - 1L, "default", CONTROLLER_ID, 1l, new ArrayList(), - IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, new ArrayList(), AMQP_URI, TEST_TOKEN); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); @@ -104,7 +110,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit final DistributionSet dsA = TestDataUtil.generateDistributionSet("", softwareManagement, distributionSetManagement); final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( - 1L, "default", CONTROLLER_ID, 1l, dsA.getModules(), IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); @@ -143,7 +149,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList); final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent( - 1L, "default", CONTROLLER_ID, 1l, dsA.getModules(), IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, dsA.getModules(), AMQP_URI, TEST_TOKEN); amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent); final Message sendMessage = createArgumentCapture(targetAssignDistributionSetEvent.getTargetAdress()); final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage); @@ -154,7 +160,19 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit if (!softwareModule.getModuleId().equals(module.getId())) { continue; } - assertFalse("The software module artifacts should not be empty", softwareModule.getArtifacts().isEmpty()); + assertThat(softwareModule.getArtifacts().size()).isEqualTo(module.getArtifacts().size()).isGreaterThan(0); + + module.getArtifacts().forEach(dbArtifact -> { + final Optional found = softwareModule.getArtifacts() + .stream().filter(dmfartifact -> dmfartifact.getFilename() + .equals(((LocalArtifact) dbArtifact).getFilename())) + .findFirst(); + + assertTrue("The artifact should exist in message", found.isPresent()); + assertThat(found.get().getSize()).isEqualTo(dbArtifact.getSize()); + assertThat(found.get().getHashes().getMd5()).isEqualTo(dbArtifact.getMd5Hash()); + assertThat(found.get().getHashes().getSha1()).isEqualTo(dbArtifact.getSha1Hash()); + }); } } @@ -162,7 +180,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit @Description("Verfies that send cancel event works") public void testSendCancelRequest() { final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent( - 1L, "default", CONTROLLER_ID, 1l, IpUtil.createAmqpUri("vHost", "mytest")); + 1L, TENANT, CONTROLLER_ID, 1L, AMQP_URI); amqpMessageDispatcherService .targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent); final Message sendMessage = createArgumentCapture(cancelTargetAssignmentDistributionSetEvent.getTargetAdress()); @@ -187,13 +205,12 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit downloadAndUpdateRequest.getActionId(), Long.valueOf(1)); assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL, sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC)); + assertEquals("Security token of target", downloadAndUpdateRequest.getTargetSecurityToken(), TEST_TOKEN); + return downloadAndUpdateRequest; } - /** - * @param sendMessage - */ private void assertEventMessage(final Message sendMessage) { assertNotNull("The message should not be null", sendMessage); diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java index 19a7be3bc..3051e4e22 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java @@ -333,20 +333,22 @@ public class AmqpMessageHandlerServiceTest { assertThat(downloadResponse.getResponseCode()).as("Message body response code is wrong") .isEqualTo(HttpStatus.OK.value()); assertThat(downloadResponse.getArtifact().getSize()).as("Wrong artifact size in message body").isEqualTo(1L); + assertThat(downloadResponse.getArtifact().getHashes().getSha1()).as("Wrong sha1 hash").isEqualTo("sha1"); + assertThat(downloadResponse.getArtifact().getHashes().getMd5()).as("Wrong md5 hash").isEqualTo("md5"); assertThat(downloadResponse.getDownloadUrl()).as("download url is wrong") .startsWith("http://localhost/api/v1/downloadserver/downloadId/"); } @Test @Description("Tests TODO") - public void lookupNextUpdateActionAfterFinished() throws IllegalArgumentException, IllegalAccessException { + public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException { // Mock final Action action = createActionWithTarget(22L, Status.FINISHED); when(controllerManagementMock.findActionWithDetails(Matchers.any())).thenReturn(action); when(controllerManagementMock.addUpdateActionStatus(Matchers.any(), Matchers.any())).thenReturn(action); // for the test the same action can be used - final List actionList = new ArrayList(); + final List actionList = new ArrayList<>(); actionList.add(action); when(controllerManagementMock.findActionByTargetAndActive(Matchers.any())).thenReturn(actionList); @@ -372,6 +374,8 @@ public class AmqpMessageHandlerServiceTest { assertThat(targetAssignDistributionSetEvent.getControllerId()).as("event has wrong controller id") .isEqualTo("target1"); + assertThat(targetAssignDistributionSetEvent.getTargetToken()).as("targetoken not filled correctly") + .isEqualTo(action.getTarget().getSecurityToken()); assertThat(targetAssignDistributionSetEvent.getActionId()).as("event has wrong action id").isEqualTo(22L); assertThat(targetAssignDistributionSetEvent.getSoftwareModules()).as("event has wrong sofware modules") .isEqualTo(softwareModuleList); @@ -379,7 +383,7 @@ public class AmqpMessageHandlerServiceTest { } private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status) { - return createActionUpdateStatus(status, 2l); + return createActionUpdateStatus(status, 2L); } private ActionUpdateStatus createActionUpdateStatus(final ActionStatus status, final Long id) { @@ -404,15 +408,14 @@ public class AmqpMessageHandlerServiceTest { } private List createSoftwareModuleList() { - final List softwareModuleList = new ArrayList(); + final List softwareModuleList = new ArrayList<>(); final SoftwareModule softwareModule = new SoftwareModule(); softwareModule.setId(777L); softwareModuleList.add(softwareModule); return softwareModuleList; } - private Action createActionWithTarget(final Long targetId, final Status status) - throws IllegalArgumentException, IllegalAccessException { + private Action createActionWithTarget(final Long targetId, final Status status) throws IllegalAccessException { // is needed for the creation of targets initalizeSecurityTokenGenerator(); @@ -427,7 +430,7 @@ public class AmqpMessageHandlerServiceTest { return action; } - private void initalizeSecurityTokenGenerator() throws IllegalArgumentException, IllegalAccessException { + private void initalizeSecurityTokenGenerator() throws IllegalAccessException { final SecurityTokenGeneratorHolder instance = SecurityTokenGeneratorHolder.getInstance(); final Field[] fields = instance.getClass().getDeclaredFields(); for (final Field field : fields) { diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java index 0bd8c164b..20d03bdd6 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/BaseAmqpServiceTest.java @@ -52,6 +52,8 @@ public class BaseAmqpServiceTest { final ActionUpdateStatus actionUpdateStatus = new ActionUpdateStatus(); actionUpdateStatus.setActionId(1L); actionUpdateStatus.setSoftwareModuleId(2L); + actionUpdateStatus.getMessage().add("Message 1"); + actionUpdateStatus.getMessage().add("Message 2"); final Message message = rabbitTemplate.getMessageConverter().toMessage(actionUpdateStatus, new MessageProperties()); diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java index 5ddb48e4f..6f86fe4a4 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/ArtifactHash.java @@ -13,10 +13,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * JSON representation of artifact hash. - * - * - * - * */ public class ArtifactHash { diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java index 4344c5416..88cb80975 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DownloadAndUpdateRequest.java @@ -19,15 +19,16 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * JSON representation of download and update request. * - * - * - * */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class DownloadAndUpdateRequest { @JsonProperty private Long actionId; + + @JsonProperty + private String targetSecurityToken; + @JsonProperty private final List softwareModules = new LinkedList<>(); @@ -39,6 +40,14 @@ public class DownloadAndUpdateRequest { this.actionId = correlator; } + public String getTargetSecurityToken() { + return targetSecurityToken; + } + + public void setTargetSecurityToken(final String targetSecurityToken) { + this.targetSecurityToken = targetSecurityToken; + } + public List getSoftwareModules() { return softwareModules; } diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java index ccc3a5b42..e4f41bc46 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java @@ -26,8 +26,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class TenantSecurityToken { 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 private final String tenant; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java index 8ef427dcf..d5e8db96f 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java @@ -18,8 +18,11 @@ import org.eclipse.hawkbit.repository.model.helper.AfterTransactionCommitExecuto import org.eclipse.hawkbit.repository.model.helper.CacheManagerHolder; import org.eclipse.hawkbit.repository.model.helper.SecurityTokenGeneratorHolder; import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder; +import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder; import org.eclipse.hawkbit.repository.model.helper.TenantAwareHolder; +import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.security.SecurityTokenGenerator; +import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; @@ -48,14 +51,24 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess @EnableAutoConfiguration public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { + /** + * @return the {@link SystemSecurityContext} singleton bean which make it + * accessible in beans which cannot access the service directly, + * e.g. JPA entities. + */ + @Bean + public SystemSecurityContextHolder systemSecurityContextHolder() { + return SystemSecurityContextHolder.getInstance(); + } + /** * @return the {@link TenantConfigurationManagement} singleton bean which * make it accessible in beans which cannot access the service * directly, e.g. JPA entities. */ @Bean - public TenantConfigurationManagement tenantConfigurationManagement() { - return TenantConfigurationManagement.getInstance(); + public TenantConfigurationManagementHolder tenantConfigurationManagementHolder() { + return TenantConfigurationManagementHolder.getInstance(); } /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/aspects/ExceptionMappingAspectHandler.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/aspects/ExceptionMappingAspectHandler.java index 3824ae80f..c3da509aa 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/aspects/ExceptionMappingAspectHandler.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/aspects/ExceptionMappingAspectHandler.java @@ -90,6 +90,8 @@ public class ExceptionMappingAspectHandler implements Ordered { + " || execution( * org.eclipse.hawkbit.controller.*.*(..)) " + " || execution( * org.eclipse.hawkbit.rest.resource.*.*(..)) " + " || execution( * org.eclipse.hawkbit.service.*.*(..)) )", throwing = "ex") + // Exception squid:S00112 - Is aspectJ proxy + @SuppressWarnings({ "squid:S00112" }) public void catchAndWrapJpaExceptionsService(final Exception ex) throws Throwable { LOG.trace("exception occured", ex); Exception translatedAccessException = translateEclipseLinkExceptionIfPossible(ex); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityChangeEventListener.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityChangeEventListener.java index 0a19d2edb..7bfbd957e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityChangeEventListener.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/EntityChangeEventListener.java @@ -20,9 +20,9 @@ import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent; import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor; import org.eclipse.hawkbit.repository.TargetRepository; -import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -67,6 +67,8 @@ public class EntityChangeEventListener { * {@link ProceedingJoinPoint#proceed()} */ @Around("execution(* org.eclipse.hawkbit.repository.TargetInfoRepository.save(..))") + // Exception squid:S00112 - Is aspectJ proxy + @SuppressWarnings({ "squid:S00112" }) public Object targetCreated(final ProceedingJoinPoint joinpoint) throws Throwable { final boolean isNew = isTargetInfoNew(joinpoint.getArgs()[0]); final Object result = joinpoint.proceed(); @@ -92,6 +94,8 @@ public class EntityChangeEventListener { * {@link ProceedingJoinPoint#proceed()} */ @Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.deleteByIdIn(..))") + // Exception squid:S00112 - Is aspectJ proxy + @SuppressWarnings({ "squid:S00112" }) public Object targetDeletedById(final ProceedingJoinPoint joinpoint) throws Throwable { final String currentTenant = tenantAware.getCurrentTenant(); final Object result = joinpoint.proceed(); @@ -111,8 +115,9 @@ public class EntityChangeEventListener { * in case exception happens in the * {@link ProceedingJoinPoint#proceed()} */ - @SuppressWarnings("unchecked") @Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.delete(..))") + // Exception squid:S00112 - Is aspectJ proxy + @SuppressWarnings({ "squid:S00112", "unchecked" }) public Object targetDeleted(final ProceedingJoinPoint joinpoint) throws Throwable { final String currentTenant = tenantAware.getCurrentTenant(); final Object result = joinpoint.proceed(); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java index b286ac6ea..68b3f1289 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetAssignDistributionSetEvent.java @@ -16,8 +16,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; /** * Event that gets sent when a distribution set gets assigned to a target. * - * - * */ public class TargetAssignDistributionSetEvent extends AbstractEvent { @@ -25,6 +23,7 @@ public class TargetAssignDistributionSetEvent extends AbstractEvent { private final String controllerId; private final Long actionId; private final URI targetAdress; + private final String targetToken; /** * Creates a new {@link TargetAssignDistributionSetEvent}. @@ -41,14 +40,18 @@ public class TargetAssignDistributionSetEvent extends AbstractEvent { * the software modules which have been assigned to the target * @param targetAdress * the targetAdress of the target + * @param targetToken + * the authentication token of the target */ public TargetAssignDistributionSetEvent(final long revision, final String tenant, final String controllerId, - final Long actionId, final Collection softwareModules, final URI targetAdress) { + final Long actionId, final Collection softwareModules, final URI targetAdress, + final String targetToken) { super(revision, tenant); this.controllerId = controllerId; this.actionId = actionId; this.softwareModules = softwareModules; this.targetAdress = targetAdress; + this.targetToken = targetToken; } /** @@ -77,4 +80,7 @@ public class TargetAssignDistributionSetEvent extends AbstractEvent { return targetAdress; } + public String getTargetToken() { + return targetToken; + } } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitDefaultServiceExecutor.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitDefaultServiceExecutor.java index 38ad38345..0d65b291e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitDefaultServiceExecutor.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/executor/AfterTransactionCommitDefaultServiceExecutor.java @@ -29,6 +29,8 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn private static final ThreadLocal> THREAD_LOCAL_RUNNABLES = new ThreadLocal<>(); @Override + // Exception squid:S1217 - Is aspectJ proxy + @SuppressWarnings({ "squid:S1217" }) public void afterCommit() { final List afterCommitRunnables = THREAD_LOCAL_RUNNABLES.get(); LOGGER.debug("Transaction successfully committed, executing {} runnables", afterCommitRunnables.size()); @@ -60,6 +62,7 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn } @Override + @SuppressWarnings({ "squid:S1217" }) public void afterCompletion(final int status) { final String transactionStatus = status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK"; LOGGER.debug("Transaction completed after commit with status {}", transactionStatus); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionRepository.java index 8221fa0ca..742a7d731 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionRepository.java @@ -29,13 +29,14 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link Action} repository. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface ActionRepository extends BaseEntityRepository, JpaSpecificationExecutor { /** * Retrieves an Action with all lazy attributes. @@ -172,7 +173,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * active */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("UPDATE Action a SET a.active = false WHERE a IN :keySet AND a.target IN :targetsIds") void setToInactive(@Param("keySet") List keySet, @Param("targetsIds") List targetsIds); @@ -191,7 +192,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the current status of the actions which are affected */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("UPDATE Action a SET a.status = :statusToSet WHERE a.target IN :targetsIds AND a.active = :active AND a.status = :currentStatus AND a.distributionSet.requiredMigrationStep = false") void switchStatus(@Param("statusToSet") Action.Status statusToSet, @Param("targetsIds") List targetIds, @Param("active") boolean active, @Param("currentStatus") Action.Status currentStatus); @@ -211,7 +212,7 @@ public interface ActionRepository extends BaseEntityRepository, Jp * the current status of the actions which are affected */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("UPDATE Action a SET a.status = :statusToSet WHERE a.rollout = :rollout AND a.active = :active AND a.status = :currentStatus") void switchStatus(@Param("statusToSet") Action.Status statusToSet, @Param("rollout") Rollout rollout, @Param("active") boolean active, @Param("currentStatus") Action.Status currentStatus); @@ -386,6 +387,4 @@ public interface ActionRepository extends BaseEntityRepository, Jp @Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status , COUNT(a.target)) FROM Action a WHERE a.rolloutGroup.id IN ?1 GROUP BY a.rolloutGroup.id, a.status") List getStatusCountByRolloutGroupId(List rolloutGroupId); - // Asha-ends here - } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionStatusRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionStatusRepository.java index 2705b9ac6..2a0e8cfb3 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionStatusRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ActionStatusRepository.java @@ -16,13 +16,14 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link ActionStatus} repository. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface ActionStatusRepository extends BaseEntityRepository, JpaSpecificationExecutor { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java index 145287fbf..024ec11cb 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java @@ -43,17 +43,15 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.hateoas.Identifiable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; /** - * service for {@link Artifact} management operations. - * - * - * + * Service for {@link Artifact} management operations. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class ArtifactManagement { @@ -108,7 +106,7 @@ public class ArtifactManagement { * if check against provided SHA1 checksum failed */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public LocalArtifact createLocalArtifact(@NotNull final InputStream stream, @NotNull final Long moduleId, @NotEmpty final String filename, final String providedMd5Sum, final String providedSha1Sum, @@ -138,7 +136,7 @@ public class ArtifactManagement { return storeArtifactMetadata(softwareModule, filename, result, existing); } - private LocalArtifact checkForExistingArtifact(final String filename, final boolean overrideExisting, + private static LocalArtifact checkForExistingArtifact(final String filename, final boolean overrideExisting, final SoftwareModule softwareModule) { if (softwareModule.getLocalArtifactByFilename(filename).isPresent()) { if (overrideExisting) { @@ -222,9 +220,7 @@ public class ArtifactManagement { artifact.setSize(result.getSize()); LOG.debug("storing new artifact into repository {}", artifact); - final LocalArtifact artifactPersisted = localArtifactRepository.save(artifact); - - return artifactPersisted; + return localArtifactRepository.save(artifact); } /** @@ -242,7 +238,7 @@ public class ArtifactManagement { * @return created {@link ExternalArtifactProvider} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public ExternalArtifactProvider createExternalArtifactProvider(@NotEmpty final String name, final String description, @NotNull final String basePath, final String defaultUrlSuffix) { @@ -268,16 +264,13 @@ public class ArtifactManagement { * if {@link SoftwareModule} with given ID does not exist */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public ExternalArtifact createExternalArtifact(@NotNull final ExternalArtifactProvider externalRepository, final String urlSuffix, @NotNull final Long moduleId) { final SoftwareModule module = getModuleAndThrowExceptionIfThatFails(moduleId); - final ExternalArtifact result = externalArtifactRepository - .save(new ExternalArtifact(externalRepository, urlSuffix, module)); - - return result; + return externalArtifactRepository.save(new ExternalArtifact(externalRepository, urlSuffix, module)); } /** @@ -290,7 +283,7 @@ public class ArtifactManagement { * */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteLocalArtifact(@NotNull final Long id) { final LocalArtifact existing = localArtifactRepository.findOne(id); @@ -313,7 +306,7 @@ public class ArtifactManagement { * the related local artifact */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteGridFsArtifact(@NotNull final LocalArtifact existing) { if (existing == null) { @@ -324,7 +317,7 @@ public class ArtifactManagement { for (final LocalArtifact lArtifact : localArtifactRepository .findByGridFsFileName(existing.getGridFsFileName())) { if (!lArtifact.getSoftwareModule().isDeleted() - && lArtifact.getSoftwareModule().getId() != existing.getSoftwareModule().getId()) { + && Long.compare(lArtifact.getSoftwareModule().getId(), existing.getSoftwareModule().getId()) != 0) { artifactIsOnlyUsedByOneSoftwareModule = false; break; } @@ -350,7 +343,7 @@ public class ArtifactManagement { * */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteExternalArtifact(@NotNull final Long id) { final ExternalArtifact existing = externalArtifactRepository.findOne(id); @@ -425,17 +418,17 @@ public class ArtifactManagement { * @param filename * of the artifact * @param overrideExisting - * to true if the artifact binary can be overdiden + * to true if the artifact binary can be overridden * if it already exists * @param contentType * the contentType of the file * * @return uploaded {@link LocalArtifact} * - * @throw ArtifactUploadFailedException if upload failes + * @throw ArtifactUploadFailedException if upload fails */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public LocalArtifact createLocalArtifact(final InputStream inputStream, final Long moduleId, final String filename, final boolean overrideExisting, final String contentType) { @@ -461,7 +454,7 @@ public class ArtifactManagement { * @throw ArtifactUploadFailedException if upload failes */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public LocalArtifact createLocalArtifact(final InputStream inputStream, final Long moduleId, final String filename, final boolean overrideExisting) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/BaseEntityRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/BaseEntityRepository.java index 2b4de2b81..16f80596d 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/BaseEntityRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/BaseEntityRepository.java @@ -14,21 +14,19 @@ import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * Command repository operations for all {@link TenantAwareBaseEntity}s. * - * - * - * * @param * type if the entity type * @param * of the entity type */ @NoRepositoryBean -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface BaseEntityRepository extends PagingAndSortingRepository { @@ -39,7 +37,7 @@ public interface BaseEntityRepository spec = (targetRoot, query, cb) -> cb.equal(targetRoot.get(Target_.controllerId), @@ -298,7 +301,7 @@ public class ControllerManagement { * @return the updated TargetInfo */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) public TargetInfo updateTargetStatus(@NotNull final TargetInfo targetInfo, final TargetUpdateStatus status, final Long lastTargetQuery, final URI address) { @@ -327,7 +330,7 @@ public class ControllerManagement { * */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) public Action addCancelActionStatus(@NotNull final ActionStatus actionStatus, final Action action) { @@ -341,13 +344,14 @@ public class ControllerManagement { break; case CANCELED: case FINISHED: - // in case of successful cancelation we also report the success at + // in case of successful cancellation we also report the success at // the canceled action itself. - actionStatus.addMessage("Cancelation completion is finished sucessfully."); + actionStatus.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Cancellation completion is finished sucessfully."); deploymentManagement.successCancellation(action); break; case RETRIEVED: - actionStatus.addMessage("Cancelation request retrieved"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Cancellation request retrieved."); break; default: } @@ -373,7 +377,7 @@ public class ControllerManagement { * inserted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) public Action addUpdateActionStatus(@NotNull final ActionStatus actionStatus, final Action action) { @@ -481,7 +485,7 @@ public class ControllerManagement { */ @Modifying @NotNull - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) public Target updateControllerAttributes(@NotEmpty final String targetid, @NotNull final Map data) { final Target target = targetRepository.findByControllerId(targetid); @@ -519,7 +523,7 @@ public class ControllerManagement { * {@link Status#RETRIEVED} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) public Action registerRetrieved(final Action action, final String message) { return handleRegisterRetrieved(action, message); @@ -583,7 +587,7 @@ public class ControllerManagement { */ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) public void addActionStatusMessage(final ActionStatus statusMessage) { actionStatusRepository.save(statusMessage); } @@ -600,7 +604,7 @@ public class ControllerManagement { * @return the security context of the target, in case no target exists for * the given controllerId {@code null} is returned */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) public String getSecurityTokenByControllerId(final String controllerId) { final Target target = targetRepository.findByControllerId(controllerId); return target != null ? target.getSecurityToken() : null; diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java index 77f71bebf..805b66d75 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java @@ -67,6 +67,7 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -78,7 +79,7 @@ import com.google.common.eventbus.EventBus; * * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class DeploymentManagement { @@ -133,7 +134,7 @@ public class DeploymentManagement { * {@link SoftwareModuleType} are not assigned as define by the * {@link DistributionSetType}. * */ - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) @@ -167,7 +168,7 @@ public class DeploymentManagement { * {@link DistributionSetType}. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID, @@ -195,9 +196,12 @@ public class DeploymentManagement { * {@link DistributionSetType}. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) + // Exception squid:S2095: see + // https://jira.sonarsource.com/browse/SONARJAVA-1478 + @SuppressWarnings({ "squid:S2095" }) public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID, final ActionType actionType, final long forcedTimestamp, @NotEmpty final String... targetIDs) { return assignDistributionSet(dsID, Arrays.stream(targetIDs) @@ -219,7 +223,7 @@ public class DeploymentManagement { * {@link DistributionSetType}. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID, @@ -243,8 +247,8 @@ public class DeploymentManagement { * a list of all targets and their action type * @param rollout * the rollout for this assignment - * @param rolloutgroup - * the rolloutgroup for this assignment + * @param rolloutGroup + * the rollout group for this assignment * @return the assignment result * * @throw IncompleteDistributionSetException if mandatory @@ -252,7 +256,7 @@ public class DeploymentManagement { * {@link DistributionSetType}. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) @CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true) public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID, @@ -276,8 +280,8 @@ public class DeploymentManagement { * a list of all targets and their action type * @param rollout * the rollout for this assignment - * @param rolloutgroup - * the rolloutgroup for this assignment + * @param rolloutGroup + * the rollout group for this assignment * @return the assignment result * * @throw IncompleteDistributionSetException if mandatory @@ -389,8 +393,8 @@ public class DeploymentManagement { softwareModules)); } - private Action createTargetAction(final Map targetsWithActionMap, final Target target, - final DistributionSet set, final Rollout rollout, final RolloutGroup rolloutGroup) { + private static Action createTargetAction(final Map targetsWithActionMap, + final Target target, final DistributionSet set, final Rollout rollout, final RolloutGroup rolloutGroup) { final Action actionForTarget = new Action(); final TargetWithActionType targetWithActionType = targetsWithActionMap.get(target.getControllerId()); actionForTarget.setActionType(targetWithActionType.getActionType()); @@ -421,13 +425,14 @@ public class DeploymentManagement { afterCommit.afterCommit(() -> { eventBus.post(new TargetInfoUpdateEvent(target.getTargetInfo())); eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), - target.getControllerId(), actionId, softwareModules, target.getTargetInfo().getAddress())); + target.getControllerId(), actionId, softwareModules, target.getTargetInfo().getAddress(), + target.getSecurityToken())); }); } /** * Removes {@link UpdateAction}s that are no longer necessary and sends - * cancelations to the controller. + * cancellations to the controller. * * @param myTarget * to override {@link UpdateAction}s @@ -512,7 +517,7 @@ public class DeploymentManagement { * action */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public Action cancelAction(@NotNull final Action action, @NotNull final Target target) { LOG.debug("cancelAction({}, {})", action, target); @@ -569,7 +574,7 @@ public class DeploymentManagement { * in case the given action is not active */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public Action forceQuitAction(@NotNull final Action action) { final Action mergedAction = entityManager.merge(action); @@ -614,7 +619,7 @@ public class DeploymentManagement { * the rolloutgroup for this action */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public void createScheduledAction(final List targets, final DistributionSet distributionSet, final ActionType actionType, final long forcedTime, final Rollout rollout, @@ -648,7 +653,7 @@ public class DeploymentManagement { * @return the action which has been started */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_SYSTEM_CODE) public Action startScheduledAction(@NotNull final Action action) { @@ -911,7 +916,7 @@ public class DeploymentManagement { * @return the updated or the found {@link TargetAction} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public Action forceTargetAction(final Long actionId) { final Action action = actionRepository.findOne(actionId); @@ -923,7 +928,7 @@ public class DeploymentManagement { } /** - * retrieves all the {@link ActionStatus} entries of the given + * Retrieves all the {@link ActionStatus} entries of the given * {@link Action} and {@link Target}. * * @param pageReq @@ -981,11 +986,11 @@ public class DeploymentManagement { * @param rollout * the rollout the actions belong to * @param rolloutGroupParent - * the parent rolloutgroup the actions should reference + * the parent rollout group the actions should reference * @param actionStatus * the status the actions have * @return the actions referring a specific rollout and a specific parent - * rolloutgroup in a specific status + * rollout group in a specific status */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_SYSTEM_CODE) diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index 8bee7c703..db1ade60e 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -59,6 +59,7 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -69,7 +70,7 @@ import com.google.common.eventbus.EventBus; * Business facade for managing the {@link DistributionSet}s. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class DistributionSetManagement { @@ -142,7 +143,7 @@ public class DistributionSetManagement { * the assignment outcome. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty final List sets, @@ -164,7 +165,7 @@ public class DistributionSetManagement { * the assignment outcome. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty final Collection dsIds, @@ -229,7 +230,7 @@ public class DistributionSetManagement { * @throw DataDependencyViolationException in case of illegal update */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSet updateDistributionSet(@NotNull final DistributionSet ds) { checkNotNull(ds.getId()); @@ -254,7 +255,7 @@ public class DistributionSetManagement { * to delete */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteDistributionSet(@NotNull final DistributionSet set) { deleteDistributionSet(set.getId()); @@ -269,7 +270,7 @@ public class DistributionSetManagement { * to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteDistributionSet(@NotEmpty final Long... distributionSetIDs) { final List toHardDelete = new ArrayList<>(); @@ -310,7 +311,7 @@ public class DistributionSetManagement { * {@link SoftwareModule}s. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public DistributionSet createDistributionSet(@NotNull final DistributionSet dSet) { prepareDsSave(dSet); @@ -344,7 +345,7 @@ public class DistributionSetManagement { * {@link SoftwareModule}s. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public List createDistributionSets(@NotNull final Iterable distributionSets) { for (final DistributionSet ds : distributionSets) { @@ -366,7 +367,7 @@ public class DistributionSetManagement { * @return the updated {@link DistributionSet}. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSet assignSoftwareModules(@NotNull final DistributionSet ds, final Set softwareModules) { @@ -388,7 +389,7 @@ public class DistributionSetManagement { * @return the updated {@link DistributionSet}. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSet unassignSoftwareModule(@NotNull final DistributionSet ds, final SoftwareModule softwareModule) { @@ -413,7 +414,7 @@ public class DistributionSetManagement { * s while the DS type is already in use. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSetType updateDistributionSetType(@NotNull final DistributionSetType dsType) { checkNotNull(dsType.getId()); @@ -715,7 +716,7 @@ public class DistributionSetManagement { * @return created {@link Entity} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public DistributionSetType createDistributionSetType(@NotNull final DistributionSetType type) { if (type.getId() != null) { @@ -732,7 +733,7 @@ public class DistributionSetManagement { * to delete */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteDistributionSetType(@NotNull final DistributionSetType type) { @@ -755,7 +756,7 @@ public class DistributionSetManagement { * in case the meta data entry already exists for the specific * key */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSetMetadata createDistributionSetMetadata(@NotNull final DistributionSetMetadata metadata) { @@ -780,7 +781,7 @@ public class DistributionSetManagement { * in case one of the meta data entry already exists for the * specific key */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public List createDistributionSetMetadata( @@ -802,7 +803,7 @@ public class DistributionSetManagement { * in case the meta data entry does not exists and cannot be * updated */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSetMetadata updateDistributionSetMetadata(@NotNull final DistributionSetMetadata metadata) { @@ -820,7 +821,7 @@ public class DistributionSetManagement { * @param id * the ID of the distribution set meta data to delete */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public void deleteDistributionSetMetadata(@NotNull final DsMetadataCompositeKey id) { @@ -913,7 +914,7 @@ public class DistributionSetManagement { * @return created {@link Entity} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public List createDistributionSetTypes(@NotNull final Collection types) { return types.stream().map(this::createDistributionSetType).collect(Collectors.toList()); @@ -926,7 +927,7 @@ public class DistributionSetManagement { * @param softwareModules */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public void checkDistributionSetAlreadyUse(final DistributionSet distributionSet) { checkDistributionSetSoftwareModulesIsAllowedToModify(distributionSet); @@ -992,14 +993,14 @@ public class DistributionSetManagement { } } - private Boolean isDSWithNoTagSelected(final DistributionSetFilter distributionSetFilter) { + private static Boolean isDSWithNoTagSelected(final DistributionSetFilter distributionSetFilter) { if (distributionSetFilter.getSelectDSWithNoTag() != null && distributionSetFilter.getSelectDSWithNoTag()) { return true; } return false; } - private Boolean isTagsSelected(final DistributionSetFilter distributionSetFilter) { + private static Boolean isTagsSelected(final DistributionSetFilter distributionSetFilter) { if (distributionSetFilter.getTagNames() != null && !distributionSetFilter.getTagNames().isEmpty()) { return true; } @@ -1033,7 +1034,7 @@ public class DistributionSetManagement { } } - private void throwMetadataKeyAlreadyExists(final String metadataKey) { + private static void throwMetadataKeyAlreadyExists(final String metadataKey) { throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); } @@ -1048,7 +1049,7 @@ public class DistributionSetManagement { * @return list of assigned ds */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public List assignTag(@NotEmpty final Collection dsIds, @@ -1077,7 +1078,7 @@ public class DistributionSetManagement { * @return list of unassigned ds */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public List unAssignAllDistributionSetsByTag(@NotNull final DistributionSetTag tag) { @@ -1095,7 +1096,7 @@ public class DistributionSetManagement { * @return the unassigned ds or if no ds is unassigned */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public DistributionSet unAssignTag(@NotNull final Long dsId, @NotNull final DistributionSetTag distributionSetTag) { final List allDs = findDistributionSetListWithDetails(Arrays.asList(dsId)); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetMetadataRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetMetadataRepository.java index 1ff6c1ca5..c042a32d0 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetMetadataRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetMetadataRepository.java @@ -12,6 +12,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.DsMetadataCompositeKey; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** @@ -20,7 +21,7 @@ import org.springframework.transaction.annotation.Transactional; * * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetMetadataRepository extends PagingAndSortingRepository, JpaSpecificationExecutor { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetRepository.java index 1a59fdca7..f2138bb2d 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetRepository.java @@ -21,6 +21,7 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** @@ -29,7 +30,7 @@ import org.springframework.transaction.annotation.Transactional; * * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetRepository extends BaseEntityRepository, JpaSpecificationExecutor { @@ -50,7 +51,7 @@ public interface DistributionSetRepository * to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("update DistributionSet d set d.deleted = 1 where d.id in :ids") void deleteDistributionSet(@Param("ids") Long... ids); @@ -62,7 +63,7 @@ public interface DistributionSetRepository * @return number of affected/deleted records */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) // Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 @Query("DELETE FROM DistributionSet d WHERE d.id IN ?1") int deleteByIdIn(Collection ids); @@ -82,7 +83,7 @@ public interface DistributionSetRepository * yet to an {@link UpdateAction}, i.e. unused. * * @param ids - * to searcgh for + * to search for * @return */ @Query("select ac.distributionSet.id from Action ac where ac.distributionSet.id in :ids") diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagRepository.java index c00713fc4..8521a96b9 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagRepository.java @@ -15,15 +15,14 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.TargetTag; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link TargetTag} repository. * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetTagRepository extends BaseEntityRepository, JpaSpecificationExecutor { /** @@ -34,7 +33,7 @@ public interface DistributionSetTagRepository * @return 1 if tag was deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) Long deleteByName(final String tagName); /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeRepository.java index b9da6b3cc..289dd6c09 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeRepository.java @@ -14,16 +14,14 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link PagingAndSortingRepository} for {@link DistributionSetType}. * - * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface DistributionSetTypeRepository extends BaseEntityRepository, JpaSpecificationExecutor { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/EclipseLinkTargetInfoRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/EclipseLinkTargetInfoRepository.java index c9be0bf38..e37a51d6c 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/EclipseLinkTargetInfoRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/EclipseLinkTargetInfoRepository.java @@ -13,7 +13,6 @@ import java.util.List; import javax.persistence.EntityManager; import javax.persistence.Query; -import javax.transaction.Transactional; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; @@ -21,16 +20,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.data.jpa.repository.Modifying; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; /** * Custom repository implementation as standard spring repository fails as of * https://bugs.eclipse.org/bugs/show_bug.cgi?id=415027 . * - * - * */ @Service -@Transactional +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public class EclipseLinkTargetInfoRepository implements TargetInfoRepository { @Autowired @@ -38,6 +37,7 @@ public class EclipseLinkTargetInfoRepository implements TargetInfoRepository { @Override @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) public void setTargetUpdateStatus(final TargetUpdateStatus status, final List targets) { final Query query = entityManager.createQuery( "update TargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status"); @@ -48,6 +48,7 @@ public class EclipseLinkTargetInfoRepository implements TargetInfoRepository { @Override @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) public S save(final S entity) { @@ -61,6 +62,7 @@ public class EclipseLinkTargetInfoRepository implements TargetInfoRepository { @Override @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) public void deleteByTargetIdIn(final Collection targetIDs) { final javax.persistence.Query query = entityManager diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactProviderRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactProviderRepository.java index 05634ef63..d0802d242 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactProviderRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactProviderRepository.java @@ -9,16 +9,14 @@ package org.eclipse.hawkbit.repository; import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * Repository for {@link ExternalArtifactProvider}. * - * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface ExternalArtifactProviderRepository extends BaseEntityRepository { } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactRepository.java index c7ece2445..d20da8013 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ExternalArtifactRepository.java @@ -11,15 +11,14 @@ package org.eclipse.hawkbit.repository; import org.eclipse.hawkbit.repository.model.ExternalArtifact; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link ExternalArtifact} repository. * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface ExternalArtifactRepository extends BaseEntityRepository { /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/LocalArtifactRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/LocalArtifactRepository.java index 5bbac1dd1..4c106957d 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/LocalArtifactRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/LocalArtifactRepository.java @@ -15,13 +15,14 @@ import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link LocalArtifact} repository. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface LocalArtifactRepository extends BaseEntityRepository { /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java index b95664d8f..326442283 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java @@ -48,14 +48,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; /** - * Service layer for generating SP reportings. + * Service layer for generating hawkBit reports. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class ReportManagement { @@ -404,7 +405,7 @@ public class ReportManagement { return innerOuterReport; } - private final class InnerOuter { + private static final class InnerOuter { final DSName name; long count; final List outer; @@ -433,9 +434,6 @@ public class ReportManagement { /** * Object contains the name and the id of an entity. * - * - * - * */ private static final class DSName { @@ -510,9 +508,6 @@ public class ReportManagement { * Return DateTypes. */ public static final class DateTypes implements Serializable { - /** - * - */ private static final long serialVersionUID = 1L; private static final PerMonth PER_MONTH = new PerMonth(); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java index 54ff37e87..d204154d0 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java @@ -43,6 +43,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -52,7 +53,7 @@ import org.springframework.validation.annotation.Validated; */ @Validated @Service -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public class RolloutGroupManagement { @Autowired @@ -189,7 +190,7 @@ public class RolloutGroupManagement { final ListJoin rolloutTargetJoin = root.join(Target_.rolloutTargetGroup); return criteriaBuilder.and(specification.toPredicate(root, query, criteriaBuilder), criteriaBuilder.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup), rolloutGroup)); - } , page); + }, page); } /** @@ -213,7 +214,7 @@ public class RolloutGroupManagement { return targetRepository.findByActionsRolloutGroup(rolloutGroup, page); } - private boolean isRolloutStatusReady(final RolloutGroup rolloutGroup) { + private static boolean isRolloutStatusReady(final RolloutGroup rolloutGroup) { return rolloutGroup != null && RolloutStatus.READY.equals(rolloutGroup.getRollout().getStatus()); } @@ -259,5 +260,4 @@ public class RolloutGroupManagement { .collect(Collectors.toList()); return new PageImpl<>(targetWithActionStatus, pageRequest, totalCount); } - -} \ No newline at end of file +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupRepository.java index cf3f3d729..e0cb4cc27 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupRepository.java @@ -18,12 +18,13 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * The repository interface for the {@link RolloutGroup} model. */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface RolloutGroupRepository extends BaseEntityRepository, JpaSpecificationExecutor { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java index 9508a6aeb..09decfc03 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java @@ -74,7 +74,7 @@ import org.springframework.validation.annotation.Validated; @Validated @Service @EnableScheduling -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public class RolloutManagement { private static final Logger LOGGER = LoggerFactory.getLogger(RolloutManagement.class); @@ -136,7 +136,7 @@ public class RolloutManagement { /** * Retrieves all rollouts. - * + * * @param page * the page request to sort and limit the result * @return a page of found rollouts @@ -148,7 +148,7 @@ public class RolloutManagement { /** * Retrieves all rollouts found by the given specification. - * + * * @param specification * the specification to filter rollouts * @param page @@ -165,7 +165,7 @@ public class RolloutManagement { /** * Retrieves a specific rollout by its ID. - * + * * @param rolloutId * the ID of the rollout to retrieve * @return the founded rollout or {@code null} if rollout with given ID does @@ -182,13 +182,13 @@ public class RolloutManagement { * which are effected by this rollout to create. The targets will then be * split up into groups. The size of the groups can be defined in the * {@code groupSize} parameter. - * + * * The rollout is not started. Only the preparation of the rollout is done, * persisting and creating all the necessary groups. The Rollout and the * groups are persisted in {@link RolloutStatus#READY} and * {@link RolloutGroupStatus#READY} so they can be started * {@link #startRollout(Rollout)}. - * + * * @param rollout * the rollout entity to create * @param amountGroup @@ -197,11 +197,11 @@ public class RolloutManagement { * the rolloutgroup conditions and actions which should be * applied for each {@link RolloutGroup} * @return the persisted rollout. - * + * * @throws IllegalArgumentException * in case the given groupSize is zero or lower. */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) public Rollout createRollout(final Rollout rollout, final int amountGroup, @@ -217,22 +217,22 @@ public class RolloutManagement { * will be done synchronously and will be returned. The targets will then be * split up into groups. The size of the groups can be defined in the * {@code groupSize} parameter. - * + * * The creation of the rollout groups is executed asynchronously due it * might take some time to split up the targets into groups. The creation of * the {@link RolloutGroup} is published as event * {@link RolloutGroupCreatedEvent}. - * + * * The rollout is in status {@link RolloutStatus#CREATING} until all rollout * groups has been created and the targets are split up, then the rollout * will change the status to {@link RolloutStatus#READY}. - * + * * The rollout is not started. Only the preparation of the rollout is done, * persisting and creating all the necessary groups. The Rollout and the * groups are persisted in {@link RolloutStatus#READY} and * {@link RolloutGroupStatus#READY} so they can be started * {@link #startRollout(Rollout)}. - * + * * @param rollout * the rollout to be created * @param amountGroup @@ -244,7 +244,7 @@ public class RolloutManagement { * @return the created rollout entity in state * {@link RolloutStatus#CREATING} */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) public Rollout createRolloutAsync(final Rollout rollout, final int amountGroup, @@ -276,7 +276,7 @@ public class RolloutManagement { return rolloutRepository.save(rollout); } - private void verifyRolloutGroupParameter(final int amountGroup) { + private static void verifyRolloutGroupParameter(final int amountGroup) { if (amountGroup <= 0) { throw new IllegalArgumentException("the amountGroup must be greater than zero"); } else if (amountGroup > 500) { @@ -284,8 +284,8 @@ public class RolloutManagement { } } - private Rollout createRolloutGroupsInNewTransaction(final int amountOfGroups, final RolloutGroupConditions conditions, - final Rollout savedRollout) { + private Rollout createRolloutGroupsInNewTransaction(final int amountOfGroups, + final RolloutGroupConditions conditions, final Rollout savedRollout) { final DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setName("creatingRollout"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); @@ -298,7 +298,7 @@ public class RolloutManagement { * sizes are calculated by dividing the total count of targets through the * amount of given groups. In same cases this will lead to less rollout * groups than given by client. - * + * * @param amountOfGroups * the amount of groups * @param conditions @@ -361,17 +361,19 @@ public class RolloutManagement { * for each affected target in the rollout. The actions of the first group * will be started immediately {@link RolloutGroupStatus#RUNNING} as the * other groups will be {@link RolloutGroupStatus#SCHEDULED} state. - * + * * The rollout itself will be then also in {@link RolloutStatus#RUNNING}. - * + * * @param rollout * the rollout to be started - * + * + * @return started rollout + * * @throws RolloutIllegalStateException * if given rollout is not in {@link RolloutStatus#READY}. Only * ready rollouts can be started. */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_SYSTEM_CODE) @@ -388,12 +390,14 @@ public class RolloutManagement { * actions of the first group will be started immediately * {@link RolloutGroupStatus#RUNNING} as the other groups will be * {@link RolloutGroupStatus#SCHEDULED} state. - * + * * The rollout itself will be then also in {@link RolloutStatus#RUNNING}. - * + * * @param rollout * the rollout to be started - * + * + * @return the started rollout + * * @throws RolloutIllegalStateException * if given rollout is not in {@link RolloutStatus#READY}. Only * ready rollouts can be started. @@ -461,19 +465,19 @@ public class RolloutManagement { * {@link RolloutGroupStatus#SCHEDULED} will not be started and keep in * {@link RolloutGroupStatus#SCHEDULED} state until the rollout is * {@link RolloutManagement#resumeRollout(Rollout)}. - * + * * Switching the rollout status to {@link RolloutStatus#PAUSED} is * sufficient due the {@link #checkRunningRollouts(long)} will not check * this rollout anymore. - * + * * @param rollout * the rollout to be paused. - * + * * @throws RolloutIllegalStateException * if given rollout is not in {@link RolloutStatus#RUNNING}. * Only running rollouts can be paused. */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_SYSTEM_CODE) @@ -496,14 +500,14 @@ public class RolloutManagement { * Resumes a paused rollout. The rollout switches back to * {@link RolloutStatus#RUNNING} state which is then picked up again by the * {@link #checkRunningRollouts(long)}. - * + * * @param rollout * the rollout to be resumed * @throws RolloutIllegalStateException * if given rollout is not in {@link RolloutStatus#PAUSED}. Only * paused rollouts can be resumed. */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_SYSTEM_CODE) @@ -521,7 +525,7 @@ public class RolloutManagement { * Checking running rollouts. Rollouts which are checked updating the * {@link Rollout#setLastCheck(long)} to indicate that the current instance * is handling the specific rollout. This code should run as system-code. - * + * *
      * {@code
      *  SystemSecurityContext.runAsSystem(new Callable() {
@@ -531,15 +535,15 @@ public class RolloutManagement {
      * });
      *  }
      * 
- * + * * This method is attend to be called by a scheduler. * {@link RolloutScheduler}. And must be running in an transaction so it's * splitted from the scheduler. - * + * * Rollouts which are currently running are investigated, by means the * error- and finish condition of running groups in this rollout are * evaluated. - * + * * @param delayBetweenChecks * the time in milliseconds of the delay between the further and * this check. This check is only applied if the last check is @@ -728,7 +732,7 @@ public class RolloutManagement { /** * Count rollouts by specified filter text. - * + * * @param searchText * name or description * @return total count rollouts for specified filter text. @@ -750,7 +754,7 @@ public class RolloutManagement { /** * * Retrieves a specific rollout by its ID. - * + * * @param pageable * the page request to sort and limit the result * @param searchText @@ -768,7 +772,7 @@ public class RolloutManagement { /** * Retrieves a specific rollout by its name. - * + * * @param rolloutName * the name of the rollout to retrieve * @return the founded rollout or {@code null} if rollout with given name @@ -781,14 +785,14 @@ public class RolloutManagement { /** * Update rollout details. - * + * * @param rollout * rollout to be updated - * + * * @return Rollout updated rollout */ @NotNull - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) public Rollout updateRollout(@NotNull final Rollout rollout) { @@ -798,7 +802,7 @@ public class RolloutManagement { /** * Get count of targets in different status in rollout. - * + * * @param page * the page request to sort and limit the result * @return a list of rollouts with details of targets count for different @@ -850,7 +854,7 @@ public class RolloutManagement { } } - private void checkIfRolloutCanStarted(final Rollout rollout, final Rollout mergedRollout) { + private static void checkIfRolloutCanStarted(final Rollout rollout, final Rollout mergedRollout) { if (!(RolloutStatus.READY.equals(mergedRollout.getStatus()))) { throw new RolloutIllegalStateException("Rollout can only be started in state ready but current state is " + rollout.getStatus().name().toLowerCase()); @@ -860,7 +864,7 @@ public class RolloutManagement { /*** * Get finished percentage details for a specified group which is in running * state. - * + * * @param rolloutId * the ID of the {@link Rollout} * @param rolloutGroup diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutRepository.java index 9c4318a3f..5a22f5ab5 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutRepository.java @@ -18,12 +18,13 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * The repository interface for the {@link Rollout} model. */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface RolloutRepository extends BaseEntityRepository, JpaSpecificationExecutor { /** @@ -40,7 +41,7 @@ public interface RolloutRepository extends BaseEntityRepository, * @return the count of the updated rows. Zero if no row has been updated */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("UPDATE Rollout r SET r.lastCheck = :lastCheck WHERE r.lastCheck < (:lastCheck - :delay) AND r.status=:status") int updateLastCheck(@Param("lastCheck") final long lastCheck, @Param("delay") final long delay, @Param("status") final RolloutStatus status); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutTargetGroupRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutTargetGroupRepository.java index 6564e2c1f..14d9b8353 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutTargetGroupRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/RolloutTargetGroupRepository.java @@ -12,11 +12,14 @@ import org.eclipse.hawkbit.repository.model.RolloutTargetGroup; import org.eclipse.hawkbit.repository.model.RolloutTargetGroupId; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; /** - * + * Spring data repository for {@link RolloutTargetGroup}. * */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface RolloutTargetGroupRepository extends CrudRepository, JpaSpecificationExecutor { } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java index 384353b8e..d719667ed 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -52,6 +52,7 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -62,7 +63,7 @@ import com.google.common.collect.Sets; * Business facade for managing {@link SoftwareModule}s. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class SoftwareManagement { @@ -108,7 +109,7 @@ public class SoftwareManagement { * of {@link SoftwareModule#getId()} is null */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public SoftwareModule updateSoftwareModule(@NotNull final SoftwareModule sm) { checkNotNull(sm.getId()); @@ -138,7 +139,7 @@ public class SoftwareManagement { * @return updated {@link Entity} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public SoftwareModuleType updateSoftwareModuleType(@NotNull final SoftwareModuleType sm) { checkNotNull(sm.getId()); @@ -283,7 +284,7 @@ public class SoftwareManagement { * is the {@link SoftwareModule} to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteSoftwareModule(@NotNull final SoftwareModule bsm) { @@ -314,10 +315,10 @@ public class SoftwareManagement { * Deletes {@link SoftwareModule}s which is any if the given ids. * * @param ids - * of the Software Moduels to be deleted + * of the Software Modules to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteSoftwareModules(@NotNull final Iterable ids) { final List swModulesToDelete = softwareModuleRepository.findByIdIn(ids); @@ -579,7 +580,7 @@ public class SoftwareManagement { return new SliceImpl<>(resultList); } - private List> buildSpecificationList(final String searchText, + private static List> buildSpecificationList(final String searchText, final SoftwareModuleType type) { final List> specList = new ArrayList<>(); if (!Strings.isNullOrEmpty(searchText)) { @@ -700,7 +701,7 @@ public class SoftwareManagement { * @return created {@link Entity} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public SoftwareModuleType createSoftwareModuleType(@NotNull final SoftwareModuleType type) { if (type.getId() != null) { @@ -718,7 +719,7 @@ public class SoftwareManagement { * @return created {@link Entity} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public List createSoftwareModuleType(@NotNull final Collection types) { return types.stream().map(this::createSoftwareModuleType).collect(Collectors.toList()); @@ -731,7 +732,7 @@ public class SoftwareManagement { * to delete */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteSoftwareModuleType(@NotNull final SoftwareModuleType type) { @@ -785,7 +786,7 @@ public class SoftwareManagement { * in case the meta data entry already exists for the specific * key */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull final SoftwareModuleMetadata metadata) { @@ -810,7 +811,7 @@ public class SoftwareManagement { * in case one of the meta data entry already exists for the * specific key */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public List createSoftwareModuleMetadata( @@ -832,7 +833,7 @@ public class SoftwareManagement { * in case the meta data entry does not exists and cannot be * updated */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull final SoftwareModuleMetadata metadata) { @@ -851,7 +852,7 @@ public class SoftwareManagement { * @param id * the ID of the software module meta data to delete */ - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public void deleteSoftwareModuleMetadata(@NotNull final SwMetadataCompositeKey id) { @@ -925,7 +926,7 @@ public class SoftwareManagement { } } - private void throwMetadataKeyAlreadyExists(final String metadataKey) { + private static void throwMetadataKeyAlreadyExists(final String metadataKey) { throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleMetadataRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleMetadataRepository.java index 0d80e1932..c40a96e92 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleMetadataRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleMetadataRepository.java @@ -16,15 +16,14 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link SoftwareModuleMetadata} repository. * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface SoftwareModuleMetadataRepository extends PagingAndSortingRepository, JpaSpecificationExecutor { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleRepository.java index d70e8226f..95b01c270 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleRepository.java @@ -21,15 +21,14 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link SoftwareModule} repository. * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface SoftwareModuleRepository extends BaseEntityRepository, JpaSpecificationExecutor { @@ -69,7 +68,7 @@ public interface SoftwareModuleRepository * */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("UPDATE SoftwareModule b SET b.deleted = 1, b.lastModifiedAt = :lastModifiedAt, b.lastModifiedBy = :lastModifiedBy WHERE b.id IN :ids") void deleteSoftwareModule(@Param("lastModifiedAt") Long modifiedAt, @Param("lastModifiedBy") String modifiedBy, @Param("ids") final Long... ids); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeRepository.java index 44b85b06b..ac9425a08 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeRepository.java @@ -12,16 +12,14 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * Repository for {@link SoftwareModuleType}. * - * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface SoftwareModuleTypeRepository extends BaseEntityRepository, JpaSpecificationExecutor { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java index be370cf2d..49c9183a7 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java @@ -35,6 +35,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -43,7 +44,7 @@ import org.springframework.validation.annotation.Validated; * Central system management operations of the SP server. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class SystemManagement { @@ -180,7 +181,7 @@ public class SystemManagement { * @return */ @Cacheable(value = "tenantMetadata", key = "#tenant.toUpperCase()") - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @NotNull public TenantMetaData getTenantMetadata(@NotNull final String tenant) { @@ -218,7 +219,7 @@ public class SystemManagement { * to delete */ @CacheEvict(value = { "tenantMetadata" }, key = "#tenant.toUpperCase()") - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN) public void deleteTenant(@NotNull final String tenant) { @@ -249,7 +250,7 @@ public class SystemManagement { * @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()} */ @Cacheable(value = "tenantMetadata", keyGenerator = "tenantKeyGenerator") - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @NotNull public TenantMetaData getTenantMetadata() { @@ -278,7 +279,7 @@ public class SystemManagement { // suspend the transaction here to do a read-request against the medata // table, when the current // tenant is not cached anyway already. - @Transactional(propagation = Propagation.NOT_SUPPORTED) + @Transactional(propagation = Propagation.NOT_SUPPORTED, isolation = Isolation.READ_UNCOMMITTED) public String currentTenant() { final String initialTenantCreation = createInitialTenant.get(); if (initialTenantCreation == null) { @@ -297,7 +298,7 @@ public class SystemManagement { * @return updated {@link TenantMetaData} entity */ @CachePut(value = "tenantMetadata", key = "#metaData.tenant.toUpperCase()") - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @NotNull public TenantMetaData updateTenantMetadata(@NotNull final TenantMetaData metaData) { @@ -341,6 +342,8 @@ public class SystemManagement { */ private class CurrentTenantKeyGenerator implements KeyGenerator { @Override + // Exception squid:S923 - override + @SuppressWarnings({ "squid:S923" }) public Object generate(final Object target, final Method method, final Object... params) { final String initialTenantCreation = createInitialTenant.get(); if (initialTenantCreation == null) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java index e0ab951ac..8db9773e6 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TagManagement.java @@ -38,21 +38,17 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import com.google.common.eventbus.EventBus; /** - * - * Mangement service class for {@link Tag}s. - * - * - * - * + * Management service class for {@link Tag}s. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class TagManagement { @@ -102,7 +98,7 @@ public class TagManagement { * if given object already exists */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) public TargetTag createTargetTag(@NotNull final TargetTag targetTag) { @@ -133,7 +129,7 @@ public class TagManagement { * if given object has already an ID. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) public List createTargetTags(@NotNull final Iterable targetTags) { @@ -155,7 +151,7 @@ public class TagManagement { * tag name of the {@link TargetTag} to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) public void deleteTargetTag(@NotEmpty final String targetTagName) { final TargetTag tag = targetTagRepository.findByNameEquals(targetTagName); @@ -220,7 +216,7 @@ public class TagManagement { * @return the new {@link TargetTag} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public TargetTag updateTargetTag(@NotNull final TargetTag targetTag) { @@ -254,7 +250,7 @@ public class TagManagement { * */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public DistributionSetTag createDistributionSetTag(@NotNull final DistributionSetTag distributionSetTag) { if (null != distributionSetTag.getId()) { @@ -282,7 +278,7 @@ public class TagManagement { * if a given entity already exists */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) public List createDistributionSetTags( @NotNull final Iterable distributionSetTags) { @@ -306,7 +302,7 @@ public class TagManagement { * to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) public void deleteDistributionSetTag(@NotEmpty final String tagName) { final DistributionSetTag tag = distributionSetTagRepository.findByNameEquals(tagName); @@ -335,7 +331,7 @@ public class TagManagement { * of {@link DistributionSetTag#getName()} is null */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) public DistributionSetTag updateDistributionSetTag(@NotNull final DistributionSetTag distributionSetTag) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java index c55127d0f..4f7c91da3 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java @@ -26,6 +26,7 @@ import org.springframework.data.jpa.domain.Specifications; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; @@ -35,10 +36,8 @@ import com.google.common.base.Strings; /** * Business service facade for managing {@link TargetFilterQuery}s. * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class TargetFilterQueryManagement { @@ -53,7 +52,7 @@ public class TargetFilterQueryManagement { * @return the created {@link TargetFilterQuery} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) public TargetFilterQuery createTargetFilterQuery(@NotNull final TargetFilterQuery customTargetFilter) { @@ -71,7 +70,7 @@ public class TargetFilterQueryManagement { * IDs of target filter query to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) public void deleteTargetFilterQuery(@NotNull final Long targetFilterQueryId) { targetFilterQueryRepository.delete(targetFilterQueryId); @@ -161,7 +160,7 @@ public class TargetFilterQueryManagement { * @return the updated {@link TargetFilterQuery} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public TargetFilterQuery updateTargetFilterQuery(@NotNull final TargetFilterQuery targetFilterQuery) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryRepository.java index b9bfcc8b6..3604785cd 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryRepository.java @@ -12,13 +12,14 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.springframework.data.domain.Page; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** - * + * Spring data repositories for {@link TargetFilterQuery}s. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TargetFilterQueryRepository extends BaseEntityRepository, JpaSpecificationExecutor { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetInfoRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetInfoRepository.java index 4582b7397..436f1e7b6 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetInfoRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetInfoRepository.java @@ -12,7 +12,6 @@ import java.util.Collection; import java.util.List; import javax.persistence.Entity; -import javax.transaction.Transactional; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; @@ -20,15 +19,16 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; /** * Usually a JPA spring data repository to handle {@link TargetInfo} entity. * However, do to an eclipselink bug with spring boot now a regular interface * that is implemented by {@link EclipseLinkTargetInfoRepository}. * - * - * */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TargetInfoRepository { /** @@ -41,7 +41,7 @@ public interface TargetInfoRepository { * to set it for */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("update TargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status") void setTargetUpdateStatus(@Param("status") TargetUpdateStatus status, @Param("targets") List targets); @@ -63,7 +63,7 @@ public interface TargetInfoRepository { * to delete */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) void deleteByTargetIdIn(final Collection targetIDs); } diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 0e0e474b2..4d6540acf 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -62,6 +62,7 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; @@ -74,7 +75,7 @@ import com.google.common.eventbus.EventBus; * Business service facade for managing {@link Target}s. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated @Service public class TargetManagement { @@ -260,7 +261,7 @@ public class TargetManagement { * @return the updated {@link Target} */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_CONTROLLER) @@ -278,7 +279,7 @@ public class TargetManagement { * @return the updated {@link Target}s */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_CONTROLLER) @@ -294,7 +295,7 @@ public class TargetManagement { * the technical IDs of the targets to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) public void deleteTargets(@NotEmpty final Long... targetIDs) { // we need to select the target IDs first to check the if the targetIDs @@ -527,11 +528,11 @@ public class TargetManagement { * @param targets * to toggle for * @param tag - * to toogle - * @return TagAssigmentResult with all metadata of the assigment outcome. + * to toggle + * @return TagAssigmentResult with all metadata of the assignment outcome. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public TargetTagAssignmentResult toggleTagAssignment(@NotEmpty final List targets, @@ -553,7 +554,7 @@ public class TargetManagement { * @return TagAssigmentResult with all metadata of the assigment outcome. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public TargetTagAssignmentResult toggleTagAssignment(@NotEmpty final Collection targetIds, @@ -596,7 +597,7 @@ public class TargetManagement { * @return list of assigned targets */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public List assignTag(@NotEmpty final Collection targetIds, @NotNull final TargetTag tag) { @@ -635,7 +636,7 @@ public class TargetManagement { * @return list of unassigned targets */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public List unAssignAllTargetsByTag(@NotNull final TargetTag tag) { @@ -652,7 +653,7 @@ public class TargetManagement { * @return the unassigned target or if no target is unassigned */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) public Target unAssignTag(@NotNull final String controllerID, @NotNull final TargetTag targetTag) { final List allTargets = targetRepository @@ -934,7 +935,7 @@ public class TargetManagement { * @return */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_CONTROLLER) @@ -972,7 +973,7 @@ public class TargetManagement { * */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_CONTROLLER) @@ -996,7 +997,7 @@ public class TargetManagement { * already exist. */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) public List createTargets(@NotNull final List targets) { @@ -1028,7 +1029,7 @@ public class TargetManagement { * @return newly created target */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @NotNull @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) public List createTargets(@NotNull final Collection targets, diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetRepository.java index 35ba39660..5e37902ab 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetRepository.java @@ -27,15 +27,14 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link Target} repository. * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TargetRepository extends BaseEntityRepository, JpaSpecificationExecutor { /** @@ -64,7 +63,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * to be deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) // Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 @Query("DELETE FROM Target t WHERE t.id IN ?1") void deleteByIdIn(final Collection targetIDs); @@ -153,7 +152,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp */ @Override @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) List save(Iterable entities); @@ -167,7 +166,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp */ @Override @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true) S save(S entity); @@ -276,7 +275,7 @@ public interface TargetRepository extends BaseEntityRepository, Jp * to update */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Query("UPDATE Target t SET t.assignedDistributionSet = :set, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy WHERE t.id IN :targets") void setAssignedDistributionSet(@Param("set") DistributionSet set, @Param("lastModifiedAt") Long modifiedAt, @Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection targets); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetTagRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetTagRepository.java index a81ed81ab..e0f03ee78 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetTagRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TargetTagRepository.java @@ -13,15 +13,14 @@ import java.util.List; import org.eclipse.hawkbit.repository.model.TargetTag; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * {@link TargetTag} repository. * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TargetTagRepository extends BaseEntityRepository, JpaSpecificationExecutor { @@ -33,7 +32,7 @@ public interface TargetTagRepository * @return 1 if tag was deleted */ @Modifying - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) Long deleteByName(final String tagName); /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java index e311cf288..c292b39e3 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java @@ -24,18 +24,19 @@ import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.env.Environment; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; /** * Central tenant configuration management operations of the SP server. */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated +@Service public class TenantConfigurationManagement implements EnvironmentAware { - private static final TenantConfigurationManagement INSTANCE = new TenantConfigurationManagement(); - @Autowired private TenantConfigurationRepository tenantConfigurationRepository; @@ -46,16 +47,6 @@ public class TenantConfigurationManagement implements EnvironmentAware { private Environment environment; - /** - * Get Singleton instance, needed for classes which are not managed in - * Spring context - * - * @return singleton instance of TenantConfigurationManagement - */ - public static TenantConfigurationManagement getInstance() { - return INSTANCE; - } - /** * Retrieves a configuration value from the e.g. tenant overwritten * configuration values or in case the tenant does not a have a specific @@ -160,7 +151,8 @@ public class TenantConfigurationManagement implements EnvironmentAware { * if the property cannot be converted to the given * {@code propertyType} */ - @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_SYSTEM_CODE) public TenantConfigurationValue getConfigurationValue(final TenantConfigurationKey configurationKey) { return getConfigurationValue(configurationKey, configurationKey.getDataType()); } @@ -185,7 +177,8 @@ public class TenantConfigurationManagement implements EnvironmentAware { * if the property cannot be converted to the given * {@code propertyType} */ - @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) + @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_SYSTEM_CODE) public T getGlobalConfigurationValue(final TenantConfigurationKey configurationKey, final Class propertyType) { @@ -221,7 +214,7 @@ public class TenantConfigurationManagement implements EnvironmentAware { * if the property cannot be converted to the given */ @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) public TenantConfigurationValue addOrUpdateConfiguration(final TenantConfigurationKey configurationKey, @@ -264,7 +257,7 @@ public class TenantConfigurationManagement implements EnvironmentAware { * the configuration key to be deleted */ @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") - @Transactional + @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) public void deleteConfiguration(final TenantConfigurationKey configurationKey) { diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationRepository.java index dd741697b..0497ea924 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationRepository.java @@ -11,13 +11,14 @@ package org.eclipse.hawkbit.repository; import java.util.List; import org.eclipse.hawkbit.repository.model.TenantConfiguration; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * The spring-data repository for the entity {@link TenantConfiguration}. * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TenantConfigurationRepository extends BaseEntityRepository { /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantMetaDataRepository.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantMetaDataRepository.java index 08d672803..4aa4c48dc 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantMetaDataRepository.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantMetaDataRepository.java @@ -12,16 +12,14 @@ import java.util.List; import org.eclipse.hawkbit.repository.model.TenantMetaData; import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * repository for operations on {@link TenantMetaData} entity. * - * - * - * */ -@Transactional(readOnly = true) +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public interface TenantMetaDataRepository extends PagingAndSortingRepository { /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java index 47f52579a..00a501540 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/TargetInfo.java @@ -38,7 +38,8 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Transient; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder; +import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.persistence.annotations.CascadeOnDelete; @@ -245,18 +246,21 @@ public class TargetInfo implements Persistable, Serializable { if (lastTargetQuery == null) { return null; } - - final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagement.getInstance() - .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); - final Duration overdueTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagement - .getInstance().getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class) - .getValue()); - final LocalDateTime currentDate = LocalDateTime.now(); - final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), - ZoneId.systemDefault()); - final LocalDateTime nextPollDate = lastPollDate.plus(pollTime); - final LocalDateTime overdueDate = nextPollDate.plus(overdueTime); - return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate); + return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> { + final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder + .getInstance().getTenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); + final Duration overdueTime = DurationHelper.formattedStringToDuration( + TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class) + .getValue()); + final LocalDateTime currentDate = LocalDateTime.now(); + final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), + ZoneId.systemDefault()); + final LocalDateTime nextPollDate = lastPollDate.plus(pollTime); + final LocalDateTime overdueDate = nextPollDate.plus(overdueTime); + return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate); + }); } /** diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemSecurityContextHolder.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemSecurityContextHolder.java new file mode 100644 index 000000000..7d005e9bc --- /dev/null +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/SystemSecurityContextHolder.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.model.helper; + +import org.eclipse.hawkbit.security.SystemSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * A singleton bean which holds {@link SystemSecurityContext} service and makes + * it accessible to beans which are not managed by spring, e.g. JPA entities. + */ +public final class SystemSecurityContextHolder { + + private static final SystemSecurityContextHolder INSTANCE = new SystemSecurityContextHolder(); + + @Autowired + private SystemSecurityContext systemSecurityContext; + + private SystemSecurityContextHolder() { + } + + /** + * @return the singleton {@link SystemSecurityContextHolder} instance + */ + public static SystemSecurityContextHolder getInstance() { + return INSTANCE; + } + + /** + * @return the {@link SystemSecurityContext} service + */ + public SystemSecurityContext getSystemSecurityContext() { + return systemSecurityContext; + } +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantConfigurationManagementHolder.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantConfigurationManagementHolder.java new file mode 100644 index 000000000..700511db6 --- /dev/null +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/model/helper/TenantConfigurationManagementHolder.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.model.helper; + +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * A singleton bean which holds {@link TenantConfigurationManagement} service + * and makes it accessible to beans which are not managed by spring, e.g. JPA + * entities. + */ +public final class TenantConfigurationManagementHolder { + + private static final TenantConfigurationManagementHolder INSTANCE = new TenantConfigurationManagementHolder(); + + @Autowired + private TenantConfigurationManagement tenantConfiguration; + + private TenantConfigurationManagementHolder() { + } + + /** + * @return the singleton {@link TenantConfigurationManagementHolder} + * instance + */ + public static TenantConfigurationManagementHolder getInstance() { + return INSTANCE; + } + + /** + * @return the {@link TenantConfigurationManagement} service + */ + public TenantConfigurationManagement getTenantConfigurationManagement() { + return tenantConfiguration; + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java index c2ed5f900..4edc46623 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/rsql/RSQLUtility.java @@ -66,10 +66,6 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor; *
  • name==targetId1,description==plugAndPlay,updateStatus==UNKNOWN
  • *
  • name==targetId1 or description==plugAndPlay or updateStatus==UNKNOWN
  • * - * - * - * - * */ public final class RSQLUtility { @@ -279,6 +275,9 @@ public final class RSQLUtility { } @Override + // Exception squid:S2095 - see + // https://jira.sonarsource.com/browse/SONARJAVA-1478 + @SuppressWarnings({ "squid:S2095" }) public List visit(final ComparisonNode node, final String param) { A fieldName = null; try { @@ -304,6 +303,9 @@ public final class RSQLUtility { return mapToPredicate(node, fieldPath, node.getArguments(), transformedValue, fieldName); } + // Exception squid:S2095 - see + // https://jira.sonarsource.com/browse/SONARJAVA-1478 + @SuppressWarnings({ "squid:S2095" }) private List getExpectedFieldList() { final List expectedFieldList = Arrays.stream(enumType.getEnumConstants()) .filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> { @@ -390,7 +392,9 @@ public final class RSQLUtility { } } - @SuppressWarnings({ "rawtypes", "unchecked" }) + // Exception squid:S2095 - see + // https://jira.sonarsource.com/browse/SONARJAVA-1478 + @SuppressWarnings({ "rawtypes", "unchecked", "squid:S2095" }) private Object transformEnumValue(final ComparisonNode node, final String value, final Class javaType) { final Class tmpEnumType = (Class) javaType; diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java index 70372fac2..d96856557 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java @@ -79,7 +79,7 @@ public class TestConfiguration implements AsyncConfigurer { } /** - * Bean for the downlod id cache. + * Bean for the download id cache. * * @return the cache */ diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java index 36fd2754b..a223c25b4 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/repository/TargetManagementTest.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -29,6 +30,7 @@ import javax.validation.ConstraintViolationException; import org.eclipse.hawkbit.AbstractIntegrationTest; import org.eclipse.hawkbit.TestDataUtil; +import org.eclipse.hawkbit.WithSpringAuthorityRule; import org.eclipse.hawkbit.WithUser; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.TenantNotExistException; @@ -724,4 +726,20 @@ public class TargetManagementTest extends AbstractIntegrationTest { assertThat(25).as("Targets with no tag").isEqualTo(targetsListWithNoTag.size()); } + + @Test + @Description("Tests the a target can be read with only the read target permission") + public void targetCanBeReadWithOnlyReadTargetPermission() throws Exception { + final String knownTargetControllerId = "readTarget"; + controllerManagament.findOrRegisterTargetIfItDoesNotexist(knownTargetControllerId, new URI("http://127.0.0.1")); + + securityRule.runAs(WithSpringAuthorityRule.withUser("bumlux", "READ_TARGET"), () -> { + final Target findTargetByControllerID = targetManagement.findTargetByControllerID(knownTargetControllerId); + assertThat(findTargetByControllerID).isNotNull(); + assertThat(findTargetByControllerID.getTargetInfo()).isNotNull(); + assertThat(findTargetByControllerID.getTargetInfo().getPollStatus()).isNotNull(); + return null; + }); + + } } diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java index c2dbd3ba5..a36443024 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/ArtifactStoreController.java @@ -143,9 +143,11 @@ public class ArtifactStoreController { actionStatus.setStatus(Status.DOWNLOAD); if (range != null) { - actionStatus.addMessage("It is a partial download request: " + range); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + + " of: " + request.getRequestURI()); } else { - actionStatus.addMessage("Target downloads"); + actionStatus.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI()); } controllerManagement.addActionStatusMessage(actionStatus); return action; diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java index e035c47ee..15c2592df 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java @@ -31,7 +31,6 @@ import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactHash; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.Link; import com.google.common.base.Charsets; @@ -40,10 +39,6 @@ import com.google.common.base.Charsets; * Utility class for the Controller API. */ public final class DataConversionHelper { - - @Autowired - ArtifactUrlHandler artifactUrlHandler; - // utility class, private constructor. private DataConversionHelper() { @@ -55,7 +50,6 @@ public final class DataConversionHelper { .map(module -> new Chunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(), module.getName(), createArtifacts(targetid, module, artifactUrlHandler))) .collect(Collectors.toList()); - } private static String mapChunkLegacyKeys(final String key) { @@ -76,29 +70,39 @@ public final class DataConversionHelper { * of the target * @param module * the software module + * * @return a list of artifacts or a empty list. Cannot be . */ public static List createArtifacts(final String targetid, final org.eclipse.hawkbit.repository.model.SoftwareModule module, final ArtifactUrlHandler artifactUrlHandler) { final List files = new ArrayList<>(); - module.getLocalArtifacts().forEach(artifact -> { - final Artifact file = new Artifact(); - file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); - file.setFilename(artifact.getFilename()); - file.setSize(artifact.getSize()); + module.getLocalArtifacts() + .forEach(artifact -> files.add(createArtifact(targetid, artifactUrlHandler, artifact))); + return files; + } + + private static Artifact createArtifact(final String targetid, final ArtifactUrlHandler artifactUrlHandler, + final LocalArtifact artifact) { + final Artifact file = new Artifact(); + file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); + file.setFilename(artifact.getFilename()); + file.setSize(artifact.getSize()); + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTP)) { final String linkHttp = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(), artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTP); + file.add(new Link(linkHttp).withRel("download-http")); + file.add(new Link(linkHttp + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum-http")); + } + + if (artifactUrlHandler.protocolSupported(UrlProtocol.HTTPS)) { final String linkHttps = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(), artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTPS); file.add(new Link(linkHttps).withRel("download")); file.add(new Link(linkHttps + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum")); - file.add(new Link(linkHttp).withRel("download-http")); - file.add(new Link(linkHttp + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum-http")); - - files.add(file); - }); - return files; + } + return file; } static ControllerBase fromTarget(final Target target, final List actions, diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java index f704acd5e..3969e1b83 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java @@ -216,9 +216,11 @@ public class RootController { statusMessage.setStatus(Status.DOWNLOAD); if (range != null) { - statusMessage.addMessage("It is a partial download request: " + range); + statusMessage.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + + " of: " + request.getRequestURI()); } else { - statusMessage.addMessage("Controller downloads"); + statusMessage.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI()); } controllerManagement.addActionStatusMessage(statusMessage); return action; @@ -316,8 +318,8 @@ public class RootController { LOG.debug("Found an active UpdateAction for target {}. returning deyploment: {}", targetid, base); - controllerManagement.registerRetrieved(action, - "Controller retrieved update action and should start now the download."); + controllerManagement.registerRetrieved(action, ControllerManagement.SERVER_MESSAGE_PREFIX + + "Target retrieved update action and should start now the download."); return new ResponseEntity<>(base, HttpStatus.OK); } @@ -388,13 +390,13 @@ public class RootController { LOG.debug("Controller confirmed cancel (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.CANCELED); - actionStatus.addMessage("Controller confirmed cancelation"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target confirmed cancelation."); break; case REJECTED: LOG.info("Controller reported internal error (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.WARNING); - actionStatus.addMessage("Controller reported internal ERROR and REJECTED update."); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target REJECTED update."); break; case CLOSED: handleClosedUpdateStatus(feedback, targetid, actionid, actionStatus); @@ -421,7 +423,8 @@ public class RootController { LOG.debug("Controller reported intermediate status (actionid: {}, targetid: {}) as we got {} report.", actionid, targetid, feedback.getStatus().getExecution()); actionStatus.setStatus(Status.RUNNING); - actionStatus.addMessage("Controller reported: " + feedback.getStatus().getExecution()); + actionStatus.addMessage( + ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported " + feedback.getStatus().getExecution()); } private static void handleClosedUpdateStatus(final ActionFeedback feedback, final String targetid, @@ -430,10 +433,10 @@ public class RootController { feedback.getStatus().getExecution()); if (feedback.getStatus().getResult().getFinished() == FinalResult.FAILURE) { actionStatus.setStatus(Status.ERROR); - actionStatus.addMessage("Controller reported CLOSED with ERROR!"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with ERROR!"); } else { actionStatus.setStatus(Status.FINISHED); - actionStatus.addMessage("Controller reported CLOSED with OK!"); + actionStatus.addMessage(ControllerManagement.SERVER_MESSAGE_PREFIX + "Target reported CLOSED with OK!"); } } @@ -494,8 +497,8 @@ public class RootController { LOG.debug("Found an active CancelAction for target {}. returning cancel: {}", targetid, cancel); - controllerManagement.registerRetrieved(action, - "Controller retrieved cancel action and should start now the cancelation."); + controllerManagement.registerRetrieved(action, ControllerManagement.SERVER_MESSAGE_PREFIX + + "Target retrieved cancel action and should start now the cancelation."); return new ResponseEntity<>(cancel, HttpStatus.OK); } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java index 3bacfac6f..77beaa698 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java @@ -19,12 +19,10 @@ import org.springframework.security.core.GrantedAuthority; * */ public class TenantUserPasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { - - /** - * - */ private static final long serialVersionUID = 1L; + // Exception squid:S1948 - no need to be Serializable + @SuppressWarnings({ "squid:S1948" }) final Object tenant; /** diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/CoapAnonymousPreAuthenticatedFilter.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/CoapAnonymousPreAuthenticatedFilter.java deleted file mode 100644 index 36a444c43..000000000 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/CoapAnonymousPreAuthenticatedFilter.java +++ /dev/null @@ -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.security; - -import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; - -/** - * A Filter for device which download via coap. - * - * - * - */ -public class CoapAnonymousPreAuthenticatedFilter implements PreAuthenficationFilter { - - @Override - public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecurityToken secruityToken) { - return new HeaderAuthentication(secruityToken.getControllerId(), TenantSecurityToken.COAP_TOKEN_VALUE); - } - - @Override - public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecurityToken secruityToken) { - return new HeaderAuthentication(secruityToken.getControllerId(), TenantSecurityToken.COAP_TOKEN_VALUE); - } - - @Override - public boolean isEnable(final TenantSecurityToken secruityToken) { - final String authHeader = secruityToken.getHeader(TenantSecurityToken.COAP_AUTHORIZATION_HEADER); - return TenantSecurityToken.COAP_TOKEN_VALUE.equals(authHeader); - } - -} diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java index b81b76e5c..b4960737d 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java @@ -24,11 +24,11 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; /** - * An spring authentication provider which supportes authentication tokens of + * An spring authentication provider which supports authentication tokens of * type {@link PreAuthenticatedAuthenticationToken} created by the * {@link ControllerPreAuthenticatedSecurityHeaderFilter}. * - * Addtionally to the authentication token providing the principal and the + * Additionally to the authentication token providing the principal and the * credentials which must be match, this authentication provider can also check * the remote IP address of the request. * diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java index 842cfcab5..4358bb734 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java @@ -22,6 +22,7 @@ import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent; import org.eclipse.hawkbit.eventbus.event.TargetTagCreatedBulkEvent; import org.eclipse.hawkbit.eventbus.event.TargetTagDeletedEvent; +import org.eclipse.hawkbit.eventbus.event.TargetTagUpdateEvent; /** * The default hawkbit event provider. @@ -39,6 +40,7 @@ public class HawkbitEventProvider implements UIEventProvider { SINGLE_EVENTS.add(DistributionSetTagUpdateEvent.class); SINGLE_EVENTS.add(RolloutGroupChangeEvent.class); SINGLE_EVENTS.add(RolloutChangeEvent.class); + SINGLE_EVENTS.add(TargetTagUpdateEvent.class); BULK_EVENTS.add(TargetCreatedEvent.class); BULK_EVENTS.add(TargetInfoUpdateEvent.class); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java index da4e2d50e..cc880fca8 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java @@ -37,6 +37,8 @@ public class UiProperties { /** * Demo user password. */ + // Exception squid:S2068 - Empty password + @SuppressWarnings({ "squid:S2068" }) private String password = ""; public String getPassword() { @@ -64,6 +66,7 @@ public class UiProperties { } } + /** * Links to potentially other systems (e.g. support, user management, * documentation etc.). @@ -227,6 +230,7 @@ public class UiProperties { } } + /** * Configuration of login view. * diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java index fe1fa9024..f2e43c1fb 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java @@ -554,7 +554,7 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C .findSoftwareModuleTypeByName(typeName.getValue()); if (createOptiongroup.getValue().equals(createTypeStr)) { if (!checkIsKeyDuplicate(typeKey.getValue()) && !checkIsDuplicate(existingType)) { - crateNewSWModuleType(); + createNewSWModuleType(); } } else { @@ -611,9 +611,9 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C /** * Create new tag. */ - private void crateNewSWModuleType() { + private void createNewSWModuleType() { int assignNumber = 0; - final String colorPicked = getColorPickedSting(); + final String colorPicked = getColorPickedString(); final String typeNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeName.getValue()); final String typeKeyValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeKey.getValue()); final String typeDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(typeDesc.getValue()); @@ -650,7 +650,7 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C * * @return String of color picked value. */ - private String getColorPickedSting() { + private String getColorPickedString() { return "rgb(" + getSelPreview().getColor().getRed() + "," + getSelPreview().getColor().getGreen() + "," + getSelPreview().getColor().getBlue() + ")"; } @@ -676,7 +676,7 @@ public class CreateUpdateSoftwareTypeLayout extends CustomComponent implements C existingType.setDescription(null != typeDescValue ? typeDescValue : null); - existingType.setColour(getColorPickedSting()); + existingType.setColour(getColorPickedString()); swTypeManagementService.updateSoftwareModuleType(existingType); uiNotification.displaySuccess(i18n.get("message.update.success", new Object[] { existingType.getName() })); closeWindow(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java index 5c0373acf..f51e171ba 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java @@ -45,20 +45,12 @@ import com.vaadin.ui.Upload.SucceededListener; * {@link StreamVariable} upload variants. * * 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, ProgressListener, StartedListener { - /** - * - */ private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(UploadHandler.class); @@ -319,11 +311,6 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene } } - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ @Override public int hashCode() { final int prime = 31; @@ -332,11 +319,6 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene return result; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ @Override public boolean equals(final Object obj) { if (this == obj) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java index d4a733de3..8fb5a8b42 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java @@ -170,6 +170,8 @@ public final class UserDetailsFormatter { 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 { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java index 360a9f925..33fcf5af9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java @@ -150,20 +150,20 @@ public abstract class AbstractTableDetailsLayout extends private void buildLayout() { final HorizontalLayout nameEditLayout = new HorizontalLayout(); - nameEditLayout.setWidth(100.0f, Unit.PERCENTAGE); + nameEditLayout.setWidth(100.0F, Unit.PERCENTAGE); nameEditLayout.addComponent(caption); - nameEditLayout.setComponentAlignment(caption, Alignment.MIDDLE_LEFT); + nameEditLayout.setComponentAlignment(caption, Alignment.TOP_LEFT); if (hasEditPermission()) { 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); addComponent(nameEditLayout); - setComponentAlignment(nameEditLayout, Alignment.MIDDLE_CENTER); + setComponentAlignment(nameEditLayout, Alignment.TOP_CENTER); addComponent(detailsTab); - setComponentAlignment(nameEditLayout, Alignment.MIDDLE_CENTER); + setComponentAlignment(nameEditLayout, Alignment.TOP_CENTER); setSizeFull(); setHeightUndefined(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTableHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTableHeader.java index b4709ccd1..b137594f8 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTableHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTableHeader.java @@ -44,7 +44,7 @@ import com.vaadin.ui.VerticalLayout; public abstract class AbstractTableHeader extends VerticalLayout { private static final long serialVersionUID = 4881626370291837175L; - + @Autowired protected I18N i18n; @@ -53,7 +53,6 @@ public abstract class AbstractTableHeader extends VerticalLayout { @Autowired protected transient EventBus.SessionEventBus eventbus; - private Label headerCaption; @@ -83,7 +82,7 @@ public abstract class AbstractTableHeader extends VerticalLayout { restoreState(); eventbus.subscribe(this); } - + @PreDestroy void destroy() { eventbus.unsubscribe(this); @@ -171,8 +170,8 @@ public abstract class AbstractTableHeader extends VerticalLayout { } titleFilterIconsLayout.addComponent(maxMinIcon); titleFilterIconsLayout.setComponentAlignment(maxMinIcon, Alignment.TOP_RIGHT); - titleFilterIconsLayout.setExpandRatio(headerCaption, 0.4f); - titleFilterIconsLayout.setExpandRatio(searchField, 0.6f); + titleFilterIconsLayout.setExpandRatio(headerCaption, 0.4F); + titleFilterIconsLayout.setExpandRatio(searchField, 0.6F); addComponent(titleFilterIconsLayout); @@ -192,10 +191,10 @@ public abstract class AbstractTableHeader extends VerticalLayout { dropHintDropFilterLayout.addComponent(dropFilterLayout); dropHintDropFilterLayout.setComponentAlignment(dropFilterLayout, Alignment.TOP_CENTER); - dropHintDropFilterLayout.setExpandRatio(dropFilterLayout, 1.0f); + dropHintDropFilterLayout.setExpandRatio(dropFilterLayout, 1.0F); } addComponent(dropHintDropFilterLayout); - setComponentAlignment(dropHintDropFilterLayout, Alignment.MIDDLE_CENTER); + setComponentAlignment(dropHintDropFilterLayout, Alignment.TOP_CENTER); addStyleName("bordered-layout"); addStyleName("no-border-bottom"); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterHeader.java index 97d2bf031..b41f3dfe9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterHeader.java @@ -290,7 +290,7 @@ public class CreateOrUpdateFilterHeader extends VerticalLayout implements Button searchLayout.setSpacing(false); searchLayout.addComponents(validationIcon, queryTextField); searchLayout.addStyleName("custom-search-layout"); - searchLayout.setComponentAlignment(validationIcon, Alignment.MIDDLE_CENTER); + searchLayout.setComponentAlignment(validationIcon, Alignment.TOP_CENTER); final HorizontalLayout iconLayout = new HorizontalLayout(); iconLayout.setSizeUndefined(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterTable.java index 6e4933d69..11121c1a5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterTable.java @@ -8,7 +8,6 @@ */ package org.eclipse.hawkbit.ui.filtermanagement; - import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -202,10 +201,7 @@ public class CreateOrUpdateFilterTable extends Table { 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.1F)); columnList.add(new TableColumn(SPUILabelDefinitions.STATUS_ICON, i18n.get("header.status"), 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)); + return columnList; } @@ -258,5 +254,5 @@ public class CreateOrUpdateFilterTable extends Table { populateTableData(); eventBus.publish(this, CustomFilterUIEvent.UPDATE_TARGET_FILTER_SEARCH_ICON); } - + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java index 2cc572245..35f88f5a1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java @@ -13,7 +13,6 @@ import java.util.List; import java.util.Map; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.ui.common.UserDetailsFormatter; import org.eclipse.hawkbit.ui.components.ProxyTarget; @@ -121,20 +120,7 @@ public class CustomTargetBeanQuery extends AbstractBeanQuery { prxyTarget.setCreatedAt(targ.getCreatedAt()); prxyTarget.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(targ)); 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.setLastTargetQuery(targ.getTargetInfo().getLastTargetQuery()); prxyTarget.setTargetInfo(targ.getTargetInfo()); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java index d3ec6245d..4f528c74a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterQueryValidation.java @@ -31,10 +31,7 @@ import cz.jirutka.rsql.parser.RSQLParserException; * * Validates the target filter query. * - * - * */ - public final class FilterQueryValidation { private static final Logger LOGGER = LoggerFactory.getLogger(FilterQueryValidation.class); @@ -103,6 +100,9 @@ public final class FilterQueryValidation { * @param expectedTokens * @return */ + // Exception squid:S2095 - see + // https://jira.sonarsource.com/browse/SONARJAVA-1478 + @SuppressWarnings({ "squid:S2095" }) public static List processExpectedTokens(final List expectedTokens) { final List expectToken = new ArrayList<>(); if (expectedTokens.size() == 2 && expectedTokens.contains(9) && expectedTokens.contains(4)) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/CreateUpdateDistributionTagLayoutWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/CreateUpdateDistributionTagLayoutWindow.java index 210509623..4d63753fe 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/CreateUpdateDistributionTagLayoutWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/CreateUpdateDistributionTagLayoutWindow.java @@ -43,10 +43,6 @@ import com.vaadin.ui.themes.ValoTheme; @SpringComponent @VaadinSessionScope public class CreateUpdateDistributionTagLayoutWindow extends CreateUpdateTagLayout { - - /** - * - */ private static final long serialVersionUID = 444276149954167545L; @Autowired @@ -288,16 +284,22 @@ public class CreateUpdateDistributionTagLayoutWindow extends CreateUpdateTagLayo } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedBulkEvent event) { populateTagNameCombo(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEvent event) { populateTagNameCombo(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdateEvent event) { populateTagNameCombo(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/DistributionTagButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/DistributionTagButtons.java index 57091b660..934d9c4c7 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/DistributionTagButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/DistributionTagButtons.java @@ -61,16 +61,22 @@ public class DistributionTagButtons extends AbstractFilterButtons { } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedBulkEvent event) { refreshTagTable(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEvent event) { refreshTagTable(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdateEvent event) { refreshTagTable(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index e48004d7a..e96a9af8e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -134,21 +134,17 @@ public class TargetBeanQuery extends AbstractBeanQuery { prxyTarget.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(targ)); prxyTarget.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(targ)); - final Target target = getTargetManagement().findTargetByControllerIDWithDetails(targ.getControllerId()); - final DistributionSet installedDistributionSet = target.getTargetInfo().getInstalledDistributionSet(); - final DistributionSet assignedDistributionSet = target.getAssignedDistributionSet(); - - prxyTarget.setInstalledDistributionSet(installedDistributionSet); - prxyTarget.setAssignedDistributionSet(assignedDistributionSet); - - if (installedDistributionSet != null) { - prxyTarget.setInstalledDistNameVersion(HawkbitCommonUtil.getFormattedNameVersion( - installedDistributionSet.getName(), installedDistributionSet.getVersion())); - } - if (assignedDistributionSet != null) { - prxyTarget.setAssignedDistNameVersion(HawkbitCommonUtil.getFormattedNameVersion( - assignedDistributionSet.getName(), assignedDistributionSet.getVersion())); + if (pinnedDistId == null) { + prxyTarget.setInstalledDistributionSet(null); + prxyTarget.setAssignedDistributionSet(null); + } else { + final Target target = getTargetManagement().findTargetByControllerIDWithDetails(targ.getControllerId()); + final DistributionSet installedDistributionSet = target.getTargetInfo().getInstalledDistributionSet(); + prxyTarget.setInstalledDistributionSet(installedDistributionSet); + final DistributionSet assignedDistributionSet = target.getAssignedDistributionSet(); + prxyTarget.setAssignedDistributionSet(assignedDistributionSet); } + prxyTarget.setUpdateStatus(targ.getTargetInfo().getUpdateStatus()); prxyTarget.setLastTargetQuery(targ.getTargetInfo().getLastTargetQuery()); prxyTarget.setTargetInfo(targ.getTargetInfo()); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java index 6232ebcf8..62ad96205 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java @@ -24,9 +24,7 @@ import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetIdName; -import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetIdName; @@ -113,7 +111,6 @@ public class TargetTable extends AbstractTable implements private static final int PROPERTY_DEPT = 3; private static final String ACTION_NOT_ALLOWED_MSG = "message.action.not.allowed"; - @Autowired private transient TargetManagement targetManagement; @@ -335,12 +332,7 @@ public class TargetTable extends AbstractTable implements if (!isMaximized()) { columnList.add(new TableColumn(SPUIDefinitions.TARGET_STATUS_POLL_TIME, "", 0.0F)); columnList.add(new TableColumn(SPUIDefinitions.TARGET_STATUS_PIN_TOGGLE_ICON, "", 0.0F)); - }else{ - columnList.add(new TableColumn(SPUILabelDefinitions.ASSIGNED_DISTRIBUTION_NAME_VER, - i18n.get("header.assigned.ds"), 0.1F)); - columnList.add(new TableColumn(SPUILabelDefinitions.INSTALLED_DISTRIBUTION_NAME_VER, - i18n.get("header.installed.ds"), 0.1F)); - } + } return columnList; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/CreateUpdateTargetTagLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/CreateUpdateTargetTagLayout.java index 51ac77f10..79a44c38c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/CreateUpdateTargetTagLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/CreateUpdateTargetTagLayout.java @@ -85,16 +85,22 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout { } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onEventTargetTagCreated(final TargetTagCreatedBulkEvent event) { populateTagNameCombo(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onEventTargetDeletedEvent(final TargetTagDeletedEvent event) { populateTagNameCombo(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onEventTargetTagUpdateEvent(final TargetTagUpdateEvent event) { populateTagNameCombo(); } @@ -144,7 +150,7 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout { final TargetTag existingTag = tagManagement.findTargetTag(tagName.getValue()); if (optiongroup.getValue().equals(createTagNw)) { if (!checkIsDuplicate(existingTag)) { - crateNewTag(); + createNewTag(); } } else { @@ -182,8 +188,8 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout { /** * Create new tag. */ - private void crateNewTag() { - final String colorPicked = getColorPickedSting(); + private void createNewTag() { + final String colorPicked = getColorPickedString(); final String tagNameValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagName.getValue()); final String tagDescValue = HawkbitCommonUtil.trimAndNullIfEmpty(tagDesc.getValue()); if (null != tagNameValue) { @@ -214,7 +220,7 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout { if (null != nameUpdateValue) { targetObj.setName(nameUpdateValue); targetObj.setDescription(null != descUpdateValue ? descUpdateValue : null); - targetObj.setColour(getColorPickedSting()); + targetObj.setColour(getColorPickedString()); tagManagement.updateTargetTag(targetObj); uiNotification.displaySuccess(i18n.get("message.update.success", new Object[] { targetObj.getName() })); closeWindow(); @@ -244,7 +250,7 @@ public class CreateUpdateTargetTagLayout extends CreateUpdateTagLayout { * * @return String of color picked value. */ - private String getColorPickedSting() { + private String getColorPickedString() { return "rgb(" + getSelPreview().getColor().getRed() + "," + getSelPreview().getColor().getGreen() + "," + getSelPreview().getColor().getBlue() + ")"; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/TargetTagFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/TargetTagFilterButtons.java index 4e5246703..48447f112 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/TargetTagFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/TargetTagFilterButtons.java @@ -267,16 +267,22 @@ public class TargetTagFilterButtons extends AbstractFilterButtons { } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onEvent(final TargetTagUpdateEvent event) { refreshContainer(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onEventTargetTagCreated(final TargetTagCreatedBulkEvent event) { refreshContainer(); } @EventBusListenerMethod(scope = EventScope.SESSION) + // Exception squid:S1172 - event not needed + @SuppressWarnings({ "squid:S1172" }) void onEventTargetDeletedEvent(final TargetTagDeletedEvent event) { refreshContainer(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java index 5a822ff86..0db3ac566 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java @@ -112,9 +112,9 @@ public final class DashboardMenu extends CustomComponent { final VerticalLayout links = buildLinksAndVersion(); menus.addComponent(links); menus.setComponentAlignment(links, Alignment.BOTTOM_CENTER); - menus.setExpandRatio(links, 1.0f); + menus.setExpandRatio(links, 1.0F); menuContent.addComponent(menus); - menuContent.setExpandRatio(menus, 1.0f); + menuContent.setExpandRatio(menus, 1.0F); dashboardMenuLayout.addComponent(menuContent); return dashboardMenuLayout; @@ -136,7 +136,7 @@ public final class DashboardMenu extends CustomComponent { final Label logo = new Label("" + i18n.get("menu.title") + "", ContentMode.HTML); logo.setSizeUndefined(); final HorizontalLayout logoWrapper = new HorizontalLayout(logo); - logoWrapper.setComponentAlignment(logo, Alignment.MIDDLE_CENTER); + logoWrapper.setComponentAlignment(logo, Alignment.TOP_CENTER); logoWrapper.addStyleName("valo-menu-title"); return logoWrapper; } @@ -225,7 +225,7 @@ public final class DashboardMenu extends CustomComponent { private VerticalLayout buildMenuItems() { final VerticalLayout menuItemsLayout = new VerticalLayout(); menuItemsLayout.addStyleName("valo-menuitems"); - menuItemsLayout.setHeight(100.0f, Unit.PERCENTAGE); + menuItemsLayout.setHeight(100.0F, Unit.PERCENTAGE); final List accessibleViews = getAccessibleViews(); if (accessibleViews.isEmpty()) { diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss index b29483da1..33ae2dd85 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/target-filter-query.scss @@ -28,12 +28,12 @@ .error-icon{ color:$success-icon-color !important; - padding:2px; + padding-left:2px !important; } .success-icon{ color:$error-icon-color !important; - padding:2px; + padding-left:2px !important; } .on-focus-no-border:focus::after{